mirror of https://gitee.com/openkylin/qemu.git
target-arm queue:
* add Cortex-A7 CPU * new ast2500 SoC model and evaluation board * palmetto-bmc: remove stray double assignment * aspeed: clean up RAM size handling * ptimer: framework for defining policy bits to change behaviour choices for different timer devices * ptimer: add some test cases * cadence_gem: add queue support * loader: support loading images to specified address spaces * loader: support auto-detect of ELF architecture from file * dma: xlnx-zynq-devcfg: Fix up XLNX_ZYNQ_DEVCFG_R_MAX * vmstateify ssd0323 * vmstateify ssi-sd * disas/arm.c: remove unused macros * imx: use 'const char', not 'char const' -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJX5BLWAAoJEDwlJe0UNgzedDEP/0eyPOuB4VLDdPGxnd/JbExh WZfXZ43CzgYQqiSlRtS+rmDSsVHXV7xlPuV5VV4FkuPPdk/+ek3pw11Ou5Tv+98T BP4ucRmL5D58koMqrwJb9GAf3a606D1Gk1NaOcl4XthdiuMRi8ARj98GwltHZmkg vjYY6ouYhGYeoJwblQ9N9466VcenrhXgL0fOSPWT48ymO9tqNHFvek267QTL3EyN 6WkrS7nak7tN2V8UyXk7oGtei54BaWjW65bMcJO6UaVbXck3u3HRdjMZhyXbXyKE 6H6bIav3Y4k+qmyFXkiA9PgsA9ZdAVge0LRwLIFDmGD6ELOwzTe+/C5sxAuZVjuO vcQv7wLPy/1gSR9yNy95mTiMJ79DvdQbnciOfSmVbm8bAglBCiiVOiCswEPjWIcp 1XrQlK7j0ZKfR7+U2Ggu6f89ruiQmIgiJmGvxeb51EbVoNLQjR8VsN+podCTX7B+ BmGx8dZYZ3DacqcaTmixdY5cnyu7AP5GXEGmOzgYvpe/vvgkpbs7xphBynFq+4j4 1CUlDlvCBZqRmy4G1zeQCl8dOLpYOMPMrYYg/2GHcYsEn+GfKTjBrTyEpcpSo889 XKCNdgLBd+bzVIpXn5GFuoHyG/M0p/OQKWx8hhxNazfAUfYpLkrGgCh++7p7UjRP yIcvj0asSHYM+HL9uIX0 =qIm/ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160922' into staging target-arm queue: * add Cortex-A7 CPU * new ast2500 SoC model and evaluation board * palmetto-bmc: remove stray double assignment * aspeed: clean up RAM size handling * ptimer: framework for defining policy bits to change behaviour choices for different timer devices * ptimer: add some test cases * cadence_gem: add queue support * loader: support loading images to specified address spaces * loader: support auto-detect of ELF architecture from file * dma: xlnx-zynq-devcfg: Fix up XLNX_ZYNQ_DEVCFG_R_MAX * vmstateify ssd0323 * vmstateify ssi-sd * disas/arm.c: remove unused macros * imx: use 'const char', not 'char const' # gpg: Signature made Thu 22 Sep 2016 18:20:22 BST # gpg: using RSA key 0x3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20160922: (36 commits) imx: Use 'const char', not 'char const' disas/arm.c: Remove unused macro definitions vmstateify ssi-sd vmstateify ssd0323 display dma: xlnx-zynq-devcfg: Fix up XLNX_ZYNQ_DEVCFG_R_MAX loader: Add AddressSpace loading support to targphys loader: Add AddressSpace loading support to uImages loader: Add AddressSpace loading support to ELFs loader: Allow a custom AddressSpace when loading ROMs loader: Use the specified MemoryRegion loader: Allow ELF loader to auto-detect the ELF arch xlnx-zynqmp: Set the number of priority queues cadence_gem: Correct indentation cadence_gem: Add queue support cadence_gem: Add support for screening cadence_gem: Add the num-priority-queues property cadence_gem: QOMify Cadence GEM tests: Add ptimer tests hw/ptimer: Suppress error messages under qtest hw/ptimer: Introduce timer policy feature ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
e678c56f16
11
disas/arm.c
11
disas/arm.c
|
@ -24,7 +24,6 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "disas/bfd.h"
|
||||
#define ISSPACE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
|
||||
|
||||
#define ARM_EXT_V1 0
|
||||
#define ARM_EXT_V2 0
|
||||
|
@ -73,15 +72,6 @@ static void floatformat_to_double (unsigned char *data, double *dest)
|
|||
|
||||
/* End of qemu specific additions. */
|
||||
|
||||
/* FIXME: Belongs in global header. */
|
||||
#ifndef strneq
|
||||
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef NUM_ELEM
|
||||
#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
|
||||
#endif
|
||||
|
||||
struct opcode32
|
||||
{
|
||||
unsigned long arch; /* Architecture defining this insn. */
|
||||
|
@ -1528,7 +1518,6 @@ static const char *const iwmmxt_cregnames[] =
|
|||
/* Default to GCC register name set. */
|
||||
static unsigned int regname_selected = 1;
|
||||
|
||||
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
|
||||
#define arm_regnames regnames[regname_selected].reg_names
|
||||
|
||||
static bfd_boolean force_thumb = false;
|
||||
|
|
|
@ -17,4 +17,4 @@ 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_FSL_IMX6) += fsl-imx6.o sabrelite.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += ast2400.o palmetto-bmc.o
|
||||
obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* 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/aspeed_soc.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
static struct arm_boot_info aspeed_board_binfo = {
|
||||
.board_id = -1, /* device-tree-only board */
|
||||
.nb_cpus = 1,
|
||||
};
|
||||
|
||||
typedef struct AspeedBoardState {
|
||||
AspeedSoCState soc;
|
||||
MemoryRegion ram;
|
||||
} AspeedBoardState;
|
||||
|
||||
typedef struct AspeedBoardConfig {
|
||||
const char *soc_name;
|
||||
uint32_t hw_strap1;
|
||||
} AspeedBoardConfig;
|
||||
|
||||
enum {
|
||||
PALMETTO_BMC,
|
||||
AST2500_EVB,
|
||||
};
|
||||
|
||||
#define PALMETTO_BMC_HW_STRAP1 ( \
|
||||
SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \
|
||||
SCU_AST2400_HW_STRAP_DRAM_CONFIG(2 /* DDR3 with CL=6, CWL=5 */) | \
|
||||
SCU_AST2400_HW_STRAP_ACPI_DIS | \
|
||||
SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(AST2400_CLK_48M_IN) | \
|
||||
SCU_HW_STRAP_VGA_CLASS_CODE | \
|
||||
SCU_HW_STRAP_LPC_RESET_PIN | \
|
||||
SCU_HW_STRAP_SPI_MODE(SCU_HW_STRAP_SPI_M_S_EN) | \
|
||||
SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(AST2400_CPU_AHB_RATIO_2_1) | \
|
||||
SCU_HW_STRAP_SPI_WIDTH | \
|
||||
SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \
|
||||
SCU_AST2400_HW_STRAP_BOOT_MODE(AST2400_SPI_BOOT))
|
||||
|
||||
#define AST2500_EVB_HW_STRAP1 (( \
|
||||
AST2500_HW_STRAP1_DEFAULTS | \
|
||||
SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE | \
|
||||
SCU_AST2500_HW_STRAP_UART_DEBUG | \
|
||||
SCU_AST2500_HW_STRAP_DDR4_ENABLE | \
|
||||
SCU_HW_STRAP_MAC1_RGMII | \
|
||||
SCU_HW_STRAP_MAC0_RGMII) & \
|
||||
~SCU_HW_STRAP_2ND_BOOT_WDT)
|
||||
|
||||
static const AspeedBoardConfig aspeed_boards[] = {
|
||||
[PALMETTO_BMC] = { "ast2400-a0", PALMETTO_BMC_HW_STRAP1 },
|
||||
[AST2500_EVB] = { "ast2500-a1", AST2500_EVB_HW_STRAP1 },
|
||||
};
|
||||
|
||||
static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
Error **errp)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
AspeedSMCFlash *fl = &s->flashes[i];
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
|
||||
/*
|
||||
* FIXME: check that we are not using a flash module exceeding
|
||||
* the controller segment size
|
||||
*/
|
||||
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
errp);
|
||||
}
|
||||
qdev_init_nofail(fl->flash);
|
||||
|
||||
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_board_init(MachineState *machine,
|
||||
const AspeedBoardConfig *cfg)
|
||||
{
|
||||
AspeedBoardState *bmc;
|
||||
AspeedSoCClass *sc;
|
||||
|
||||
bmc = g_new0(AspeedBoardState, 1);
|
||||
object_initialize(&bmc->soc, (sizeof(bmc->soc)), cfg->soc_name);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(&bmc->soc),
|
||||
&error_abort);
|
||||
|
||||
sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
|
||||
|
||||
object_property_set_int(OBJECT(&bmc->soc), ram_size, "ram-size",
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
/*
|
||||
* Allocate RAM after the memory controller has checked the size
|
||||
* was valid. If not, a default value is used.
|
||||
*/
|
||||
ram_size = object_property_get_int(OBJECT(&bmc->soc), "ram-size",
|
||||
&error_abort);
|
||||
|
||||
memory_region_allocate_system_memory(&bmc->ram, NULL, "ram", ram_size);
|
||||
memory_region_add_subregion(get_system_memory(), sc->info->sdram_base,
|
||||
&bmc->ram);
|
||||
object_property_add_const_link(OBJECT(&bmc->soc), "ram", OBJECT(&bmc->ram),
|
||||
&error_abort);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort);
|
||||
|
||||
aspeed_board_binfo.kernel_filename = machine->kernel_filename;
|
||||
aspeed_board_binfo.initrd_filename = machine->initrd_filename;
|
||||
aspeed_board_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
aspeed_board_binfo.ram_size = ram_size;
|
||||
aspeed_board_binfo.loader_start = sc->info->sdram_base;
|
||||
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &aspeed_board_binfo);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_init(MachineState *machine)
|
||||
{
|
||||
aspeed_board_init(machine, &aspeed_boards[PALMETTO_BMC]);
|
||||
}
|
||||
|
||||
static void palmetto_bmc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)";
|
||||
mc->init = palmetto_bmc_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo palmetto_bmc_type = {
|
||||
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = palmetto_bmc_class_init,
|
||||
};
|
||||
|
||||
static void ast2500_evb_init(MachineState *machine)
|
||||
{
|
||||
aspeed_board_init(machine, &aspeed_boards[AST2500_EVB]);
|
||||
}
|
||||
|
||||
static void ast2500_evb_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
|
||||
mc->desc = "Aspeed AST2500 EVB (ARM1176)";
|
||||
mc->init = ast2500_evb_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->no_sdcard = 1;
|
||||
mc->no_floppy = 1;
|
||||
mc->no_cdrom = 1;
|
||||
mc->no_parallel = 1;
|
||||
}
|
||||
|
||||
static const TypeInfo ast2500_evb_type = {
|
||||
.name = MACHINE_TYPE_NAME("ast2500-evb"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = ast2500_evb_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_machine_init(void)
|
||||
{
|
||||
type_register_static(&palmetto_bmc_type);
|
||||
type_register_static(&ast2500_evb_type);
|
||||
}
|
||||
|
||||
type_init(aspeed_machine_init)
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* AST2400 SoC
|
||||
* ASPEED SoC family
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
* Jeremy Kerr <jk@ozlabs.org>
|
||||
|
@ -15,59 +15,68 @@
|
|||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/arm/ast2400.h"
|
||||
#include "hw/arm/aspeed_soc.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
|
||||
#define AST2400_UART_5_BASE 0x00184000
|
||||
#define AST2400_IOMEM_SIZE 0x00200000
|
||||
#define AST2400_IOMEM_BASE 0x1E600000
|
||||
#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */
|
||||
#define AST2400_FMC_BASE 0X1E620000
|
||||
#define AST2400_SPI_BASE 0X1E630000
|
||||
#define AST2400_VIC_BASE 0x1E6C0000
|
||||
#define AST2400_SDMC_BASE 0x1E6E0000
|
||||
#define AST2400_SCU_BASE 0x1E6E2000
|
||||
#define AST2400_TIMER_BASE 0x1E782000
|
||||
#define AST2400_I2C_BASE 0x1E78A000
|
||||
#define ASPEED_SOC_UART_5_BASE 0x00184000
|
||||
#define ASPEED_SOC_IOMEM_SIZE 0x00200000
|
||||
#define ASPEED_SOC_IOMEM_BASE 0x1E600000
|
||||
#define ASPEED_SOC_FMC_BASE 0x1E620000
|
||||
#define ASPEED_SOC_SPI_BASE 0x1E630000
|
||||
#define ASPEED_SOC_VIC_BASE 0x1E6C0000
|
||||
#define ASPEED_SOC_SDMC_BASE 0x1E6E0000
|
||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||
|
||||
#define AST2400_FMC_FLASH_BASE 0x20000000
|
||||
#define AST2400_SPI_FLASH_BASE 0x30000000
|
||||
#define ASPEED_SOC_FMC_FLASH_BASE 0x20000000
|
||||
#define ASPEED_SOC_SPI_FLASH_BASE 0x30000000
|
||||
|
||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||
static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
|
||||
|
||||
#define AST2400_SDRAM_BASE 0x40000000
|
||||
#define AST2500_SDRAM_BASE 0x80000000
|
||||
|
||||
static const AspeedSoCInfo aspeed_socs[] = {
|
||||
{ "ast2400-a0", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE },
|
||||
{ "ast2400", "arm926", AST2400_A0_SILICON_REV, AST2400_SDRAM_BASE },
|
||||
{ "ast2500-a1", "arm1176", AST2500_A1_SILICON_REV, AST2500_SDRAM_BASE },
|
||||
};
|
||||
|
||||
/*
|
||||
* 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)
|
||||
static uint64_t aspeed_soc_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,
|
||||
static void aspeed_soc_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,
|
||||
static const MemoryRegionOps aspeed_soc_io_ops = {
|
||||
.read = aspeed_soc_io_read,
|
||||
.write = aspeed_soc_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ast2400_init(Object *obj)
|
||||
static void aspeed_soc_init(Object *obj)
|
||||
{
|
||||
AST2400State *s = AST2400(obj);
|
||||
AspeedSoCState *s = ASPEED_SOC(obj);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
|
||||
|
||||
s->cpu = cpu_arm_init("arm926");
|
||||
s->cpu = cpu_arm_init(sc->info->cpu_model);
|
||||
|
||||
object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC);
|
||||
object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL);
|
||||
|
@ -85,7 +94,7 @@ static void ast2400_init(Object *obj)
|
|||
object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default());
|
||||
qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev",
|
||||
AST2400_A0_SILICON_REV);
|
||||
sc->info->silicon_rev);
|
||||
object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu),
|
||||
"hw-strap1", &error_abort);
|
||||
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
|
||||
|
@ -103,20 +112,22 @@ static void ast2400_init(Object *obj)
|
|||
object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default());
|
||||
qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev",
|
||||
AST2400_A0_SILICON_REV);
|
||||
sc->info->silicon_rev);
|
||||
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
|
||||
"ram-size", &error_abort);
|
||||
}
|
||||
|
||||
static void ast2400_realize(DeviceState *dev, Error **errp)
|
||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int i;
|
||||
AST2400State *s = AST2400(dev);
|
||||
AspeedSoCState *s = ASPEED_SOC(dev);
|
||||
Error *err = NULL, *local_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);
|
||||
memory_region_init_io(&s->iomem, NULL, &aspeed_soc_io_ops, NULL,
|
||||
"aspeed_soc.io", ASPEED_SOC_IOMEM_SIZE);
|
||||
memory_region_add_subregion_overlap(get_system_memory(),
|
||||
ASPEED_SOC_IOMEM_BASE, &s->iomem, -1);
|
||||
|
||||
/* VIC */
|
||||
object_property_set_bool(OBJECT(&s->vic), true, "realized", &err);
|
||||
|
@ -124,7 +135,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, ASPEED_SOC_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,
|
||||
|
@ -136,7 +147,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, ASPEED_SOC_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);
|
||||
|
@ -148,12 +159,12 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, ASPEED_SOC_SCU_BASE);
|
||||
|
||||
/* 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,
|
||||
serial_mm_init(&s->iomem, ASPEED_SOC_UART_5_BASE, 2,
|
||||
uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
|
@ -163,7 +174,7 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, ASPEED_SOC_I2C_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 12));
|
||||
|
||||
|
@ -175,8 +186,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, ASPEED_SOC_FMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, ASPEED_SOC_FMC_FLASH_BASE);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0,
|
||||
qdev_get_gpio_in(DEVICE(&s->vic), 19));
|
||||
|
||||
|
@ -188,8 +199,8 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, ASPEED_SOC_SPI_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, ASPEED_SOC_SPI_FLASH_BASE);
|
||||
|
||||
/* SDMC - SDRAM Memory Controller */
|
||||
object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err);
|
||||
|
@ -197,14 +208,16 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
|
|||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, AST2400_SDMC_BASE);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
||||
}
|
||||
|
||||
static void ast2400_class_init(ObjectClass *oc, void *data)
|
||||
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc);
|
||||
|
||||
dc->realize = ast2400_realize;
|
||||
sc->info = (AspeedSoCInfo *) data;
|
||||
dc->realize = aspeed_soc_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
|
@ -213,17 +226,29 @@ static void ast2400_class_init(ObjectClass *oc, void *data)
|
|||
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 const TypeInfo aspeed_soc_type_info = {
|
||||
.name = TYPE_ASPEED_SOC,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_init = aspeed_soc_init,
|
||||
.instance_size = sizeof(AspeedSoCState),
|
||||
.class_size = sizeof(AspeedSoCClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void ast2400_register_types(void)
|
||||
static void aspeed_soc_register_types(void)
|
||||
{
|
||||
type_register_static(&ast2400_type_info);
|
||||
int i;
|
||||
|
||||
type_register_static(&aspeed_soc_type_info);
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_socs); ++i) {
|
||||
TypeInfo ti = {
|
||||
.name = aspeed_socs[i].name,
|
||||
.parent = TYPE_ASPEED_SOC,
|
||||
.class_init = aspeed_soc_class_init,
|
||||
.class_data = (void *) &aspeed_socs[i],
|
||||
};
|
||||
type_register(&ti);
|
||||
}
|
||||
}
|
||||
|
||||
type_init(ast2400_register_types)
|
||||
type_init(aspeed_soc_register_types)
|
|
@ -837,7 +837,7 @@ static void mv88w8618_timer_init(SysBusDevice *dev, mv88w8618_timer_state *s,
|
|||
s->freq = freq;
|
||||
|
||||
bh = qemu_bh_new(mv88w8618_timer_tick, s);
|
||||
s->ptimer = ptimer_init(bh);
|
||||
s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
}
|
||||
|
||||
static uint64_t mv88w8618_pit_read(void *opaque, hwaddr offset,
|
||||
|
|
|
@ -1,102 +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"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.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_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
Error **errp)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
AspeedSMCFlash *fl = &s->flashes[i];
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
|
||||
/*
|
||||
* FIXME: check that we are not using a flash module exceeding
|
||||
* the controller segment size
|
||||
*/
|
||||
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
errp);
|
||||
}
|
||||
qdev_init_nofail(fl->flash);
|
||||
|
||||
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
||||
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_int(OBJECT(&bmc->soc), 0x120CE416, "hw-strap1",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
|
||||
&error_abort);
|
||||
|
||||
palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
|
||||
palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &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);
|
|
@ -332,6 +332,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
|
||||
qdev_set_nic_properties(DEVICE(&s->gem[i]), nd);
|
||||
}
|
||||
object_property_set_int(OBJECT(&s->gem[i]), 2, "num-priority-queues",
|
||||
&error_abort);
|
||||
object_property_set_bool(OBJECT(&s->gem[i]), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -133,9 +133,15 @@ ssize_t read_targphys(const char *name,
|
|||
return did;
|
||||
}
|
||||
|
||||
/* return the size or -1 if error */
|
||||
int load_image_targphys(const char *filename,
|
||||
hwaddr addr, uint64_t max_sz)
|
||||
{
|
||||
return load_image_targphys_as(filename, addr, max_sz, NULL);
|
||||
}
|
||||
|
||||
/* return the size or -1 if error */
|
||||
int load_image_targphys_as(const char *filename,
|
||||
hwaddr addr, uint64_t max_sz, AddressSpace *as)
|
||||
{
|
||||
int size;
|
||||
|
||||
|
@ -144,7 +150,7 @@ int load_image_targphys(const char *filename,
|
|||
return -1;
|
||||
}
|
||||
if (size > 0) {
|
||||
rom_add_file_fixed(filename, addr, -1);
|
||||
rom_add_file_fixed_as(filename, addr, -1, as);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
@ -416,6 +422,18 @@ 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)
|
||||
{
|
||||
return load_elf_as(filename, translate_fn, translate_opaque, pentry,
|
||||
lowaddr, highaddr, big_endian, elf_machine, clear_lsb,
|
||||
data_swab, NULL);
|
||||
}
|
||||
|
||||
/* return < 0 if error, otherwise the number of bytes loaded in memory */
|
||||
int load_elf_as(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, AddressSpace *as)
|
||||
{
|
||||
int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
|
@ -455,11 +473,11 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
|||
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);
|
||||
data_swab, as);
|
||||
} else {
|
||||
ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb,
|
||||
data_swab);
|
||||
data_swab, as);
|
||||
}
|
||||
|
||||
fail:
|
||||
|
@ -569,7 +587,7 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
|
|||
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)
|
||||
void *translate_opaque, AddressSpace *as)
|
||||
{
|
||||
int fd;
|
||||
int size;
|
||||
|
@ -670,7 +688,7 @@ static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
|||
hdr->ih_size = bytes;
|
||||
}
|
||||
|
||||
rom_add_blob_fixed(filename, data, hdr->ih_size, address);
|
||||
rom_add_blob_fixed_as(filename, data, hdr->ih_size, address, as);
|
||||
|
||||
ret = hdr->ih_size;
|
||||
|
||||
|
@ -686,14 +704,23 @@ int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
|||
void *translate_opaque)
|
||||
{
|
||||
return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL,
|
||||
translate_fn, translate_opaque);
|
||||
translate_fn, translate_opaque, NULL);
|
||||
}
|
||||
|
||||
int load_uimage_as(const char *filename, hwaddr *ep, hwaddr *loadaddr,
|
||||
int *is_linux,
|
||||
uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, AddressSpace *as)
|
||||
{
|
||||
return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL,
|
||||
translate_fn, translate_opaque, as);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Load a gzip-compressed kernel to a dynamically allocated buffer. */
|
||||
|
@ -777,6 +804,7 @@ struct Rom {
|
|||
|
||||
uint8_t *data;
|
||||
MemoryRegion *mr;
|
||||
AddressSpace *as;
|
||||
int isrom;
|
||||
char *fw_dir;
|
||||
char *fw_file;
|
||||
|
@ -788,6 +816,12 @@ struct Rom {
|
|||
static FWCfgState *fw_cfg;
|
||||
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
|
||||
|
||||
static inline bool rom_order_compare(Rom *rom, Rom *item)
|
||||
{
|
||||
return (rom->as > item->as) ||
|
||||
(rom->as == item->as && rom->addr >= item->addr);
|
||||
}
|
||||
|
||||
static void rom_insert(Rom *rom)
|
||||
{
|
||||
Rom *item;
|
||||
|
@ -796,10 +830,16 @@ static void rom_insert(Rom *rom)
|
|||
hw_error ("ROM images must be loaded at startup\n");
|
||||
}
|
||||
|
||||
/* list is ordered by load address */
|
||||
/* The user didn't specify an address space, this is the default */
|
||||
if (!rom->as) {
|
||||
rom->as = &address_space_memory;
|
||||
}
|
||||
|
||||
/* List is ordered by load address in the same address space */
|
||||
QTAILQ_FOREACH(item, &roms, next) {
|
||||
if (rom->addr >= item->addr)
|
||||
if (rom_order_compare(rom, item)) {
|
||||
continue;
|
||||
}
|
||||
QTAILQ_INSERT_BEFORE(item, rom, next);
|
||||
return;
|
||||
}
|
||||
|
@ -833,16 +873,25 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
|||
|
||||
int rom_add_file(const char *file, const char *fw_dir,
|
||||
hwaddr addr, int32_t bootindex,
|
||||
bool option_rom, MemoryRegion *mr)
|
||||
bool option_rom, MemoryRegion *mr,
|
||||
AddressSpace *as)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
Rom *rom;
|
||||
int rc, fd = -1;
|
||||
char devpath[100];
|
||||
|
||||
if (as && mr) {
|
||||
fprintf(stderr, "Specifying an Address Space and Memory Region is " \
|
||||
"not valid when loading a rom\n");
|
||||
/* We haven't allocated anything so we don't need any cleanup */
|
||||
return -1;
|
||||
}
|
||||
|
||||
rom = g_malloc0(sizeof(*rom));
|
||||
rom->name = g_strdup(file);
|
||||
rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
|
||||
rom->as = as;
|
||||
if (rom->path == NULL) {
|
||||
rom->path = g_strdup(file);
|
||||
}
|
||||
|
@ -969,7 +1018,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
|
|||
* 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)
|
||||
size_t romsize, hwaddr addr, AddressSpace *as)
|
||||
{
|
||||
Rom *rom;
|
||||
|
||||
|
@ -979,18 +1028,19 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize,
|
|||
rom->datasize = datasize;
|
||||
rom->romsize = romsize;
|
||||
rom->data = data;
|
||||
rom->as = as;
|
||||
rom_insert(rom);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rom_add_vga(const char *file)
|
||||
{
|
||||
return rom_add_file(file, "vgaroms", 0, -1, true, NULL);
|
||||
return rom_add_file(file, "vgaroms", 0, -1, true, NULL, NULL);
|
||||
}
|
||||
|
||||
int rom_add_option(const char *file, int32_t bootindex)
|
||||
{
|
||||
return rom_add_file(file, "genroms", 0, bootindex, true, NULL);
|
||||
return rom_add_file(file, "genroms", 0, bootindex, true, NULL, NULL);
|
||||
}
|
||||
|
||||
static void rom_reset(void *unused)
|
||||
|
@ -1008,8 +1058,8 @@ static void rom_reset(void *unused)
|
|||
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);
|
||||
cpu_physical_memory_write_rom(rom->as, rom->addr, rom->data,
|
||||
rom->datasize);
|
||||
}
|
||||
if (rom->isrom) {
|
||||
/* rom needs to be written only once */
|
||||
|
@ -1031,12 +1081,13 @@ int rom_check_and_register_reset(void)
|
|||
hwaddr addr = 0;
|
||||
MemoryRegionSection section;
|
||||
Rom *rom;
|
||||
AddressSpace *as = NULL;
|
||||
|
||||
QTAILQ_FOREACH(rom, &roms, next) {
|
||||
if (rom->fw_file) {
|
||||
continue;
|
||||
}
|
||||
if (addr > rom->addr) {
|
||||
if ((addr > rom->addr) && (as == rom->as)) {
|
||||
fprintf(stderr, "rom: requested regions overlap "
|
||||
"(rom %s. free=0x" TARGET_FMT_plx
|
||||
", addr=0x" TARGET_FMT_plx ")\n",
|
||||
|
@ -1045,9 +1096,11 @@ int rom_check_and_register_reset(void)
|
|||
}
|
||||
addr = rom->addr;
|
||||
addr += rom->romsize;
|
||||
section = memory_region_find(get_system_memory(), rom->addr, 1);
|
||||
section = memory_region_find(rom->mr ? rom->mr : get_system_memory(),
|
||||
rom->addr, 1);
|
||||
rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr);
|
||||
memory_region_unref(section.mr);
|
||||
as = rom->as;
|
||||
}
|
||||
qemu_register_reset(rom_reset, NULL);
|
||||
roms_loaded = 1;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "hw/ptimer.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
struct ptimer_state
|
||||
{
|
||||
|
@ -21,6 +22,7 @@ struct ptimer_state
|
|||
int64_t period;
|
||||
int64_t last_event;
|
||||
int64_t next_event;
|
||||
uint8_t policy_mask;
|
||||
QEMUBH *bh;
|
||||
QEMUTimer *timer;
|
||||
};
|
||||
|
@ -43,7 +45,10 @@ static void ptimer_reload(ptimer_state *s)
|
|||
s->delta = s->limit;
|
||||
}
|
||||
if (s->delta == 0 || s->period == 0) {
|
||||
fprintf(stderr, "Timer with period zero, disabling\n");
|
||||
if (!qtest_enabled()) {
|
||||
fprintf(stderr, "Timer with period zero, disabling\n");
|
||||
}
|
||||
timer_del(s->timer);
|
||||
s->enabled = 0;
|
||||
return;
|
||||
}
|
||||
|
@ -161,7 +166,9 @@ void ptimer_run(ptimer_state *s, int oneshot)
|
|||
bool was_disabled = !s->enabled;
|
||||
|
||||
if (was_disabled && s->period == 0) {
|
||||
fprintf(stderr, "Timer with period zero, disabling\n");
|
||||
if (!qtest_enabled()) {
|
||||
fprintf(stderr, "Timer with period zero, disabling\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
s->enabled = oneshot ? 2 : 1;
|
||||
|
@ -242,12 +249,13 @@ const VMStateDescription vmstate_ptimer = {
|
|||
}
|
||||
};
|
||||
|
||||
ptimer_state *ptimer_init(QEMUBH *bh)
|
||||
ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask)
|
||||
{
|
||||
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);
|
||||
s->policy_mask = policy_mask;
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -48,18 +48,18 @@ 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;
|
||||
uint32_t cmd_len;
|
||||
int32_t cmd;
|
||||
int32_t cmd_data[8];
|
||||
int32_t row;
|
||||
int32_t row_start;
|
||||
int32_t row_end;
|
||||
int32_t col;
|
||||
int32_t col_start;
|
||||
int32_t col_end;
|
||||
int32_t redraw;
|
||||
int32_t remap;
|
||||
uint32_t mode;
|
||||
uint8_t framebuffer[128 * 80 / 2];
|
||||
} ssd0323_state;
|
||||
|
||||
|
@ -279,83 +279,62 @@ static void ssd0323_cd(void *opaque, int n, int level)
|
|||
s->mode = level ? SSD0323_DATA : SSD0323_CMD;
|
||||
}
|
||||
|
||||
static void ssd0323_save(QEMUFile *f, void *opaque)
|
||||
static int ssd0323_post_load(void *opaque, int version_id)
|
||||
{
|
||||
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)) {
|
||||
if (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 VMStateDescription vmstate_ssd0323 = {
|
||||
.name = "ssd0323_oled",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = ssd0323_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT32(cmd_len, ssd0323_state),
|
||||
VMSTATE_INT32(cmd, ssd0323_state),
|
||||
VMSTATE_INT32_ARRAY(cmd_data, ssd0323_state, 8),
|
||||
VMSTATE_INT32(row, ssd0323_state),
|
||||
VMSTATE_INT32(row_start, ssd0323_state),
|
||||
VMSTATE_INT32(row_end, ssd0323_state),
|
||||
VMSTATE_INT32(col, ssd0323_state),
|
||||
VMSTATE_INT32(col_start, ssd0323_state),
|
||||
VMSTATE_INT32(col_end, ssd0323_state),
|
||||
VMSTATE_INT32(redraw, ssd0323_state),
|
||||
VMSTATE_INT32(remap, ssd0323_state),
|
||||
VMSTATE_UINT32(mode, ssd0323_state),
|
||||
VMSTATE_BUFFER(framebuffer, ssd0323_state),
|
||||
VMSTATE_SSI_SLAVE(ssidev, ssd0323_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const GraphicHwOps ssd0323_ops = {
|
||||
.invalidate = ssd0323_invalidate_display,
|
||||
.gfx_update = ssd0323_update_display,
|
||||
|
@ -372,18 +351,17 @@ static void ssd0323_realize(SSISlave *d, Error **errp)
|
|||
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);
|
||||
}
|
||||
|
||||
static void ssd0323_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||
|
||||
k->realize = ssd0323_realize;
|
||||
k->transfer = ssd0323_transfer;
|
||||
k->cs_polarity = SSI_CS_HIGH;
|
||||
dc->vmsd = &vmstate_ssd0323;
|
||||
}
|
||||
|
||||
static const TypeInfo ssd0323_info = {
|
||||
|
|
|
@ -548,7 +548,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
st->nr = i;
|
||||
st->bh = qemu_bh_new(timer_hit, st);
|
||||
st->ptimer = ptimer_init(st->bh);
|
||||
st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(st->ptimer, s->freqhz);
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -139,7 +139,7 @@ static m5206_timer_state *m5206_timer_init(qemu_irq irq)
|
|||
|
||||
s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state));
|
||||
bh = qemu_bh_new(m5206_timer_trigger, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
s->irq = irq;
|
||||
m5206_timer_reset(s);
|
||||
return s;
|
||||
|
|
|
@ -183,7 +183,7 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
|
|||
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);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
memory_region_init_io(&s->iomem, NULL, &m5208_timer_ops, s,
|
||||
"m5208-timer", 0x00004000);
|
||||
memory_region_add_subregion(address_space, 0xfc080000 + 0x4000 * i,
|
||||
|
|
|
@ -120,6 +120,41 @@ static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
|
|||
[BMC_DEV_ID] = 0x00002402U
|
||||
};
|
||||
|
||||
/* SCU70 bit 23: 0 24Mhz. bit 11:9: 0b001 AXI:ABH ratio 2:1 */
|
||||
/* AST2500 revision A1 */
|
||||
|
||||
static const uint32_t ast2500_a1_resets[ASPEED_SCU_NR_REGS] = {
|
||||
[SYS_RST_CTRL] = 0xFFCFFEDCU,
|
||||
[CLK_SEL] = 0xF3F40000U,
|
||||
[CLK_STOP_CTRL] = 0x19FC3E8BU,
|
||||
[D2PLL_PARAM] = 0x00026108U,
|
||||
[MPLL_PARAM] = 0x00030291U,
|
||||
[HPLL_PARAM] = 0x93000400U,
|
||||
[MISC_CTRL1] = 0x00000010U,
|
||||
[PCI_CTRL1] = 0x20001A03U,
|
||||
[PCI_CTRL2] = 0x20001A03U,
|
||||
[PCI_CTRL3] = 0x04000030U,
|
||||
[SYS_RST_STATUS] = 0x00000001U,
|
||||
[SOC_SCRATCH1] = 0x000000C0U, /* SoC completed DRAM init */
|
||||
[MISC_CTRL2] = 0x00000023U,
|
||||
[RNG_CTRL] = 0x0000000EU,
|
||||
[PINMUX_CTRL2] = 0x0000F000U,
|
||||
[PINMUX_CTRL3] = 0x03000000U,
|
||||
[PINMUX_CTRL4] = 0x00000000U,
|
||||
[PINMUX_CTRL5] = 0x0000A000U,
|
||||
[WDT_RST_CTRL] = 0x023FFFF3U,
|
||||
[PINMUX_CTRL8] = 0xFFFF0000U,
|
||||
[PINMUX_CTRL9] = 0x000FFFFFU,
|
||||
[FREE_CNTR4] = 0x000000FFU,
|
||||
[FREE_CNTR4_EXT] = 0x000000FFU,
|
||||
[CPU2_BASE_SEG1] = 0x80000000U,
|
||||
[CPU2_BASE_SEG4] = 0x1E600000U,
|
||||
[CPU2_BASE_SEG5] = 0xC0000000U,
|
||||
[UART_HPLL_CLK] = 0x00001903U,
|
||||
[PCIE_CTRL] = 0x0000007BU,
|
||||
[BMC_DEV_ID] = 0x00002402U
|
||||
};
|
||||
|
||||
static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
AspeedSCUState *s = ASPEED_SCU(opaque);
|
||||
|
@ -198,6 +233,10 @@ static void aspeed_scu_reset(DeviceState *dev)
|
|||
case AST2400_A0_SILICON_REV:
|
||||
reset = ast2400_a0_resets;
|
||||
break;
|
||||
case AST2500_A0_SILICON_REV:
|
||||
case AST2500_A1_SILICON_REV:
|
||||
reset = ast2500_a1_resets;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -208,7 +247,11 @@ static void aspeed_scu_reset(DeviceState *dev)
|
|||
s->regs[HW_STRAP2] = s->hw_strap2;
|
||||
}
|
||||
|
||||
static uint32_t aspeed_silicon_revs[] = { AST2400_A0_SILICON_REV, };
|
||||
static uint32_t aspeed_silicon_revs[] = {
|
||||
AST2400_A0_SILICON_REV,
|
||||
AST2500_A0_SILICON_REV,
|
||||
AST2500_A1_SILICON_REV,
|
||||
};
|
||||
|
||||
bool is_supported_silicon_rev(uint32_t silicon_rev)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/misc/aspeed_sdmc.h"
|
||||
#include "hw/misc/aspeed_scu.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
|
@ -139,9 +140,9 @@ static const MemoryRegionOps aspeed_sdmc_ops = {
|
|||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static int ast2400_rambits(void)
|
||||
static int ast2400_rambits(AspeedSDMCState *s)
|
||||
{
|
||||
switch (ram_size >> 20) {
|
||||
switch (s->ram_size >> 20) {
|
||||
case 64:
|
||||
return ASPEED_SDMC_DRAM_64MB;
|
||||
case 128:
|
||||
|
@ -151,18 +152,19 @@ static int ast2400_rambits(void)
|
|||
case 512:
|
||||
return ASPEED_SDMC_DRAM_512MB;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x"
|
||||
RAM_ADDR_FMT "\n", __func__, ram_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* set a minimum default */
|
||||
return ASPEED_SDMC_DRAM_64MB;
|
||||
/* use a common default */
|
||||
error_report("warning: Invalid RAM size 0x%" PRIx64
|
||||
". Using default 256M", s->ram_size);
|
||||
s->ram_size = 256 << 20;
|
||||
return ASPEED_SDMC_DRAM_256MB;
|
||||
}
|
||||
|
||||
static int ast2500_rambits(void)
|
||||
static int ast2500_rambits(AspeedSDMCState *s)
|
||||
{
|
||||
switch (ram_size >> 20) {
|
||||
switch (s->ram_size >> 20) {
|
||||
case 128:
|
||||
return ASPEED_SDMC_AST2500_128MB;
|
||||
case 256:
|
||||
|
@ -172,13 +174,14 @@ static int ast2500_rambits(void)
|
|||
case 1024:
|
||||
return ASPEED_SDMC_AST2500_1024MB;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid RAM size: 0x"
|
||||
RAM_ADDR_FMT "\n", __func__, ram_size);
|
||||
break;
|
||||
}
|
||||
|
||||
/* set a minimum default */
|
||||
return ASPEED_SDMC_AST2500_128MB;
|
||||
/* use a common default */
|
||||
error_report("warning: Invalid RAM size 0x%" PRIx64
|
||||
". Using default 512M", s->ram_size);
|
||||
s->ram_size = 512 << 20;
|
||||
return ASPEED_SDMC_AST2500_512MB;
|
||||
}
|
||||
|
||||
static void aspeed_sdmc_reset(DeviceState *dev)
|
||||
|
@ -192,14 +195,15 @@ static void aspeed_sdmc_reset(DeviceState *dev)
|
|||
case AST2400_A0_SILICON_REV:
|
||||
s->regs[R_CONF] |=
|
||||
ASPEED_SDMC_VGA_COMPAT |
|
||||
ASPEED_SDMC_DRAM_SIZE(ast2400_rambits());
|
||||
ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
|
||||
break;
|
||||
|
||||
case AST2500_A0_SILICON_REV:
|
||||
case AST2500_A1_SILICON_REV:
|
||||
s->regs[R_CONF] |=
|
||||
ASPEED_SDMC_HW_VERSION(1) |
|
||||
ASPEED_SDMC_VGA_APERTURE(ASPEED_SDMC_VGA_64MB) |
|
||||
ASPEED_SDMC_DRAM_SIZE(ast2500_rambits());
|
||||
ASPEED_SDMC_DRAM_SIZE(s->ram_bits);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -218,6 +222,18 @@ static void aspeed_sdmc_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
switch (s->silicon_rev) {
|
||||
case AST2400_A0_SILICON_REV:
|
||||
s->ram_bits = ast2400_rambits(s);
|
||||
break;
|
||||
case AST2500_A0_SILICON_REV:
|
||||
case AST2500_A1_SILICON_REV:
|
||||
s->ram_bits = ast2500_rambits(s);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_sdmc_ops, s,
|
||||
TYPE_ASPEED_SDMC, 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
@ -235,6 +251,7 @@ static const VMStateDescription vmstate_aspeed_sdmc = {
|
|||
|
||||
static Property aspeed_sdmc_properties[] = {
|
||||
DEFINE_PROP_UINT32("silicon-rev", AspeedSDMCState, silicon_rev, 0),
|
||||
DEFINE_PROP_UINT64("ram-size", AspeedSDMCState, ram_size, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx25_ccm_reg_name(uint32_t reg)
|
||||
static const char *imx25_ccm_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx31_ccm_reg_name(uint32_t reg)
|
||||
static const char *imx31_ccm_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx6_ccm_reg_name(uint32_t reg)
|
||||
static const char *imx6_ccm_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
@ -99,7 +99,7 @@ static char const *imx6_ccm_reg_name(uint32_t reg)
|
|||
}
|
||||
}
|
||||
|
||||
static char const *imx6_analog_reg_name(uint32_t reg)
|
||||
static const char *imx6_analog_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx6_src_reg_name(uint32_t reg)
|
||||
static const char *imx6_src_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <zlib.h> /* For crc32 */
|
||||
|
||||
#include "hw/net/cadence_gem.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "net/checksum.h"
|
||||
|
||||
#ifdef CADENCE_GEM_ERR_DEBUG
|
||||
|
@ -141,6 +143,61 @@
|
|||
#define GEM_DESCONF6 (0x00000294/4)
|
||||
#define GEM_DESCONF7 (0x00000298/4)
|
||||
|
||||
#define GEM_INT_Q1_STATUS (0x00000400 / 4)
|
||||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
|
||||
#define GEM_TRANSMIT_Q1_PTR (0x00000440 / 4)
|
||||
#define GEM_TRANSMIT_Q15_PTR (GEM_TRANSMIT_Q1_PTR + 14)
|
||||
|
||||
#define GEM_RECEIVE_Q1_PTR (0x00000480 / 4)
|
||||
#define GEM_RECEIVE_Q15_PTR (GEM_RECEIVE_Q1_PTR + 14)
|
||||
|
||||
#define GEM_INT_Q1_ENABLE (0x00000600 / 4)
|
||||
#define GEM_INT_Q7_ENABLE (GEM_INT_Q1_ENABLE + 6)
|
||||
#define GEM_INT_Q8_ENABLE (0x00000660 / 4)
|
||||
#define GEM_INT_Q15_ENABLE (GEM_INT_Q8_ENABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_DISABLE (0x00000620 / 4)
|
||||
#define GEM_INT_Q7_DISABLE (GEM_INT_Q1_DISABLE + 6)
|
||||
#define GEM_INT_Q8_DISABLE (0x00000680 / 4)
|
||||
#define GEM_INT_Q15_DISABLE (GEM_INT_Q8_DISABLE + 7)
|
||||
|
||||
#define GEM_INT_Q1_MASK (0x00000640 / 4)
|
||||
#define GEM_INT_Q7_MASK (GEM_INT_Q1_MASK + 6)
|
||||
#define GEM_INT_Q8_MASK (0x000006A0 / 4)
|
||||
#define GEM_INT_Q15_MASK (GEM_INT_Q8_MASK + 7)
|
||||
|
||||
#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4)
|
||||
|
||||
#define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29)
|
||||
#define GEM_ST1R_DSTC_ENABLE (1 << 28)
|
||||
#define GEM_ST1R_UDP_PORT_MATCH_SHIFT (12)
|
||||
#define GEM_ST1R_UDP_PORT_MATCH_WIDTH (27 - GEM_ST1R_UDP_PORT_MATCH_SHIFT + 1)
|
||||
#define GEM_ST1R_DSTC_MATCH_SHIFT (4)
|
||||
#define GEM_ST1R_DSTC_MATCH_WIDTH (11 - GEM_ST1R_DSTC_MATCH_SHIFT + 1)
|
||||
#define GEM_ST1R_QUEUE_SHIFT (0)
|
||||
#define GEM_ST1R_QUEUE_WIDTH (3 - GEM_ST1R_QUEUE_SHIFT + 1)
|
||||
|
||||
#define GEM_SCREENING_TYPE2_REGISTER_0 (0x00000540 / 4)
|
||||
|
||||
#define GEM_ST2R_COMPARE_A_ENABLE (1 << 18)
|
||||
#define GEM_ST2R_COMPARE_A_SHIFT (13)
|
||||
#define GEM_ST2R_COMPARE_WIDTH (17 - GEM_ST2R_COMPARE_A_SHIFT + 1)
|
||||
#define GEM_ST2R_ETHERTYPE_ENABLE (1 << 12)
|
||||
#define GEM_ST2R_ETHERTYPE_INDEX_SHIFT (9)
|
||||
#define GEM_ST2R_ETHERTYPE_INDEX_WIDTH (11 - GEM_ST2R_ETHERTYPE_INDEX_SHIFT \
|
||||
+ 1)
|
||||
#define GEM_ST2R_QUEUE_SHIFT (0)
|
||||
#define GEM_ST2R_QUEUE_WIDTH (3 - GEM_ST2R_QUEUE_SHIFT + 1)
|
||||
|
||||
#define GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 (0x000006e0 / 4)
|
||||
#define GEM_TYPE2_COMPARE_0_WORD_0 (0x00000700 / 4)
|
||||
|
||||
#define GEM_T2CW1_COMPARE_OFFSET_SHIFT (7)
|
||||
#define GEM_T2CW1_COMPARE_OFFSET_WIDTH (8 - GEM_T2CW1_COMPARE_OFFSET_SHIFT + 1)
|
||||
#define GEM_T2CW1_OFFSET_VALUE_SHIFT (0)
|
||||
#define GEM_T2CW1_OFFSET_VALUE_WIDTH (6 - GEM_T2CW1_OFFSET_VALUE_SHIFT + 1)
|
||||
|
||||
/*****************************************/
|
||||
#define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */
|
||||
#define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */
|
||||
|
@ -284,9 +341,9 @@ static inline unsigned tx_desc_get_length(unsigned *desc)
|
|||
return desc[1] & DESC_1_LENGTH;
|
||||
}
|
||||
|
||||
static inline void print_gem_tx_desc(unsigned *desc)
|
||||
static inline void print_gem_tx_desc(unsigned *desc, uint8_t queue)
|
||||
{
|
||||
DB_PRINT("TXDESC:\n");
|
||||
DB_PRINT("TXDESC (queue %" PRId8 "):\n", queue);
|
||||
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));
|
||||
|
@ -416,6 +473,7 @@ static void phy_update_link(CadenceGEMState *s)
|
|||
static int gem_can_receive(NetClientState *nc)
|
||||
{
|
||||
CadenceGEMState *s;
|
||||
int i;
|
||||
|
||||
s = qemu_get_nic_opaque(nc);
|
||||
|
||||
|
@ -428,18 +486,20 @@ static int gem_can_receive(NetClientState *nc)
|
|||
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);
|
||||
for (i = 0; i < s->num_priority_queues; i++) {
|
||||
if (rx_desc_get_ownership(s->rx_desc[i]) == 1) {
|
||||
if (s->can_rx_state != 2) {
|
||||
s->can_rx_state = 2;
|
||||
DB_PRINT("can't receive - busy buffer descriptor (q%d) 0x%x\n",
|
||||
i, s->rx_desc_addr[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->can_rx_state != 0) {
|
||||
s->can_rx_state = 0;
|
||||
DB_PRINT("can receive 0x%x\n", s->rx_desc_addr);
|
||||
DB_PRINT("can receive\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -450,9 +510,20 @@ static int gem_can_receive(NetClientState *nc)
|
|||
*/
|
||||
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);
|
||||
int i;
|
||||
|
||||
if ((s->num_priority_queues == 1) && s->regs[GEM_ISR]) {
|
||||
/* No priority queues, just trigger the interrupt */
|
||||
DB_PRINT("asserting int.\n", i);
|
||||
qemu_set_irq(s->irq[0], 1);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
if (s->regs[GEM_INT_Q1_STATUS + i]) {
|
||||
DB_PRINT("asserting int. (q=%d)\n", i);
|
||||
qemu_set_irq(s->irq[i], 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,17 +672,137 @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
|
|||
return GEM_RX_REJECT;
|
||||
}
|
||||
|
||||
static void gem_get_rx_desc(CadenceGEMState *s)
|
||||
/* Figure out which queue the received data should be sent to */
|
||||
static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
|
||||
unsigned rxbufsize)
|
||||
{
|
||||
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr);
|
||||
uint32_t reg;
|
||||
bool matched, mismatched;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < s->num_type1_screeners; i++) {
|
||||
reg = s->regs[GEM_SCREENING_TYPE1_REGISTER_0 + i];
|
||||
matched = false;
|
||||
mismatched = false;
|
||||
|
||||
/* Screening is based on UDP Port */
|
||||
if (reg & GEM_ST1R_UDP_PORT_MATCH_ENABLE) {
|
||||
uint16_t udp_port = rxbuf_ptr[14 + 22] << 8 | rxbuf_ptr[14 + 23];
|
||||
if (udp_port == extract32(reg, GEM_ST1R_UDP_PORT_MATCH_SHIFT,
|
||||
GEM_ST1R_UDP_PORT_MATCH_WIDTH)) {
|
||||
matched = true;
|
||||
} else {
|
||||
mismatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Screening is based on DS/TC */
|
||||
if (reg & GEM_ST1R_DSTC_ENABLE) {
|
||||
uint8_t dscp = rxbuf_ptr[14 + 1];
|
||||
if (dscp == extract32(reg, GEM_ST1R_DSTC_MATCH_SHIFT,
|
||||
GEM_ST1R_DSTC_MATCH_WIDTH)) {
|
||||
matched = true;
|
||||
} else {
|
||||
mismatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched && !mismatched) {
|
||||
return extract32(reg, GEM_ST1R_QUEUE_SHIFT, GEM_ST1R_QUEUE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_type2_screeners; i++) {
|
||||
reg = s->regs[GEM_SCREENING_TYPE2_REGISTER_0 + i];
|
||||
matched = false;
|
||||
mismatched = false;
|
||||
|
||||
if (reg & GEM_ST2R_ETHERTYPE_ENABLE) {
|
||||
uint16_t type = rxbuf_ptr[12] << 8 | rxbuf_ptr[13];
|
||||
int et_idx = extract32(reg, GEM_ST2R_ETHERTYPE_INDEX_SHIFT,
|
||||
GEM_ST2R_ETHERTYPE_INDEX_WIDTH);
|
||||
|
||||
if (et_idx > s->num_type2_screeners) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Out of range ethertype "
|
||||
"register index: %d\n", et_idx);
|
||||
}
|
||||
if (type == s->regs[GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 +
|
||||
et_idx]) {
|
||||
matched = true;
|
||||
} else {
|
||||
mismatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare A, B, C */
|
||||
for (j = 0; j < 3; j++) {
|
||||
uint32_t cr0, cr1, mask;
|
||||
uint16_t rx_cmp;
|
||||
int offset;
|
||||
int cr_idx = extract32(reg, GEM_ST2R_COMPARE_A_SHIFT + j * 6,
|
||||
GEM_ST2R_COMPARE_WIDTH);
|
||||
|
||||
if (!(reg & (GEM_ST2R_COMPARE_A_ENABLE << (j * 6)))) {
|
||||
continue;
|
||||
}
|
||||
if (cr_idx > s->num_type2_screeners) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Out of range compare "
|
||||
"register index: %d\n", cr_idx);
|
||||
}
|
||||
|
||||
cr0 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2];
|
||||
cr1 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2 + 1];
|
||||
offset = extract32(cr1, GEM_T2CW1_OFFSET_VALUE_SHIFT,
|
||||
GEM_T2CW1_OFFSET_VALUE_WIDTH);
|
||||
|
||||
switch (extract32(cr1, GEM_T2CW1_COMPARE_OFFSET_SHIFT,
|
||||
GEM_T2CW1_COMPARE_OFFSET_WIDTH)) {
|
||||
case 3: /* Skip UDP header */
|
||||
qemu_log_mask(LOG_UNIMP, "TCP compare offsets"
|
||||
"unimplemented - assuming UDP\n");
|
||||
offset += 8;
|
||||
/* Fallthrough */
|
||||
case 2: /* skip the IP header */
|
||||
offset += 20;
|
||||
/* Fallthrough */
|
||||
case 1: /* Count from after the ethertype */
|
||||
offset += 14;
|
||||
break;
|
||||
case 0:
|
||||
/* Offset from start of frame */
|
||||
break;
|
||||
}
|
||||
|
||||
rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset];
|
||||
mask = extract32(cr0, 0, 16);
|
||||
|
||||
if ((rx_cmp & mask) == (extract32(cr0, 16, 16) & mask)) {
|
||||
matched = true;
|
||||
} else {
|
||||
mismatched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched && !mismatched) {
|
||||
return extract32(reg, GEM_ST2R_QUEUE_SHIFT, GEM_ST2R_QUEUE_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
/* We made it here, assume it's queue 0 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gem_get_rx_desc(CadenceGEMState *s, int q)
|
||||
{
|
||||
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[q]);
|
||||
/* read current descriptor */
|
||||
cpu_physical_memory_read(s->rx_desc_addr,
|
||||
(uint8_t *)s->rx_desc, sizeof(s->rx_desc));
|
||||
cpu_physical_memory_read(s->rx_desc_addr[0],
|
||||
(uint8_t *)s->rx_desc[0], sizeof(s->rx_desc[0]));
|
||||
|
||||
/* Descriptor owned by software ? */
|
||||
if (rx_desc_get_ownership(s->rx_desc) == 1) {
|
||||
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
|
||||
DB_PRINT("descriptor 0x%x owned by sw.\n",
|
||||
(unsigned)s->rx_desc_addr);
|
||||
(unsigned)s->rx_desc_addr[q]);
|
||||
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
|
||||
s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
|
||||
/* Handle interrupt consequences */
|
||||
|
@ -632,6 +823,7 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||
uint8_t *rxbuf_ptr;
|
||||
bool first_desc = true;
|
||||
int maf;
|
||||
int q = 0;
|
||||
|
||||
s = qemu_get_nic_opaque(nc);
|
||||
|
||||
|
@ -710,6 +902,9 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||
|
||||
DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
|
||||
|
||||
/* Find which queue we are targetting */
|
||||
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
|
||||
|
||||
while (bytes_to_copy) {
|
||||
/* Do nothing if receive is not enabled. */
|
||||
if (!gem_can_receive(nc)) {
|
||||
|
@ -718,56 +913,59 @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|||
}
|
||||
|
||||
DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
|
||||
rx_desc_get_buffer(s->rx_desc));
|
||||
rx_desc_get_buffer(s->rx_desc[q]));
|
||||
|
||||
/* Copy packet data to emulated DMA buffer */
|
||||
cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc) + rxbuf_offset,
|
||||
cpu_physical_memory_write(rx_desc_get_buffer(s->rx_desc[q]) +
|
||||
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);
|
||||
rx_desc_set_sof(s->rx_desc[q]);
|
||||
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_eof(s->rx_desc[q]);
|
||||
rx_desc_set_length(s->rx_desc[q], size);
|
||||
}
|
||||
rx_desc_set_ownership(s->rx_desc);
|
||||
rx_desc_set_ownership(s->rx_desc[q]);
|
||||
|
||||
switch (maf) {
|
||||
case GEM_RX_PROMISCUOUS_ACCEPT:
|
||||
break;
|
||||
case GEM_RX_BROADCAST_ACCEPT:
|
||||
rx_desc_set_broadcast(s->rx_desc);
|
||||
rx_desc_set_broadcast(s->rx_desc[q]);
|
||||
break;
|
||||
case GEM_RX_UNICAST_HASH_ACCEPT:
|
||||
rx_desc_set_unicast_hash(s->rx_desc);
|
||||
rx_desc_set_unicast_hash(s->rx_desc[q]);
|
||||
break;
|
||||
case GEM_RX_MULTICAST_HASH_ACCEPT:
|
||||
rx_desc_set_multicast_hash(s->rx_desc);
|
||||
rx_desc_set_multicast_hash(s->rx_desc[q]);
|
||||
break;
|
||||
case GEM_RX_REJECT:
|
||||
abort();
|
||||
default: /* SAR */
|
||||
rx_desc_set_sar(s->rx_desc, maf);
|
||||
rx_desc_set_sar(s->rx_desc[q], maf);
|
||||
}
|
||||
|
||||
/* Descriptor write-back. */
|
||||
cpu_physical_memory_write(s->rx_desc_addr,
|
||||
(uint8_t *)s->rx_desc, sizeof(s->rx_desc));
|
||||
cpu_physical_memory_write(s->rx_desc_addr[q],
|
||||
(uint8_t *)s->rx_desc[q],
|
||||
sizeof(s->rx_desc[q]));
|
||||
|
||||
/* Next descriptor */
|
||||
if (rx_desc_get_wrap(s->rx_desc)) {
|
||||
if (rx_desc_get_wrap(s->rx_desc[q])) {
|
||||
DB_PRINT("wrapping RX descriptor list\n");
|
||||
s->rx_desc_addr = s->regs[GEM_RXQBASE];
|
||||
s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
|
||||
} else {
|
||||
DB_PRINT("incrementing RX descriptor list\n");
|
||||
s->rx_desc_addr += 8;
|
||||
s->rx_desc_addr[q] += 8;
|
||||
}
|
||||
gem_get_rx_desc(s);
|
||||
|
||||
gem_get_rx_desc(s, q);
|
||||
}
|
||||
|
||||
/* Count it */
|
||||
|
@ -839,6 +1037,7 @@ static void gem_transmit(CadenceGEMState *s)
|
|||
uint8_t tx_packet[2048];
|
||||
uint8_t *p;
|
||||
unsigned total_bytes;
|
||||
int q = 0;
|
||||
|
||||
/* Do nothing if transmit is not enabled. */
|
||||
if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
|
||||
|
@ -854,110 +1053,123 @@ static void gem_transmit(CadenceGEMState *s)
|
|||
p = tx_packet;
|
||||
total_bytes = 0;
|
||||
|
||||
/* read current descriptor */
|
||||
packet_desc_addr = s->tx_desc_addr;
|
||||
for (q = s->num_priority_queues - 1; q >= 0; q--) {
|
||||
/* read current descriptor */
|
||||
packet_desc_addr = s->tx_desc_addr[q];
|
||||
|
||||
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)) {
|
||||
tx_desc_set_last(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));
|
||||
}
|
||||
/* Handle all descriptors owned by hardware */
|
||||
while (tx_desc_get_used(desc) == 0) {
|
||||
|
||||
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);
|
||||
/* Do nothing if transmit is not enabled. */
|
||||
if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
|
||||
return;
|
||||
}
|
||||
print_gem_tx_desc(desc, q);
|
||||
|
||||
/* 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[q],
|
||||
(uint8_t *)desc_first,
|
||||
sizeof(desc_first));
|
||||
tx_desc_set_used(desc_first);
|
||||
cpu_physical_memory_write(s->tx_desc_addr[q],
|
||||
(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[q] = s->regs[GEM_TXQBASE];
|
||||
} else {
|
||||
s->tx_desc_addr[q] = packet_desc_addr + 8;
|
||||
}
|
||||
DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
|
||||
|
||||
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
|
||||
s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
|
||||
|
||||
/* Update queue interrupt status */
|
||||
if (s->num_priority_queues > 1) {
|
||||
s->regs[GEM_INT_Q1_STATUS + q] |=
|
||||
GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]);
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
tx_desc_set_last(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1065,7 +1277,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|||
{
|
||||
CadenceGEMState *s;
|
||||
uint32_t retval;
|
||||
|
||||
int i;
|
||||
s = (CadenceGEMState *)opaque;
|
||||
|
||||
offset >>= 2;
|
||||
|
@ -1075,8 +1287,10 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|||
|
||||
switch (offset) {
|
||||
case GEM_ISR:
|
||||
DB_PRINT("lowering irq on ISR read\n");
|
||||
qemu_set_irq(s->irq, 0);
|
||||
DB_PRINT("lowering irqs on ISR read\n");
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
qemu_set_irq(s->irq[i], 0);
|
||||
}
|
||||
break;
|
||||
case GEM_PHYMNTNC:
|
||||
if (retval & GEM_PHYMNTNC_OP_R) {
|
||||
|
@ -1101,6 +1315,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|||
retval &= ~(s->regs_wo[offset]);
|
||||
|
||||
DB_PRINT("0x%08x\n", retval);
|
||||
gem_update_int_status(s);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -1113,6 +1328,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
{
|
||||
CadenceGEMState *s = (CadenceGEMState *)opaque;
|
||||
uint32_t readonly;
|
||||
int i;
|
||||
|
||||
DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
|
||||
offset >>= 2;
|
||||
|
@ -1132,14 +1348,18 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
switch (offset) {
|
||||
case GEM_NWCTRL:
|
||||
if (val & GEM_NWCTRL_RXENA) {
|
||||
gem_get_rx_desc(s);
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
gem_get_rx_desc(s, i);
|
||||
}
|
||||
}
|
||||
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];
|
||||
for (i = 0; i < s->num_priority_queues; i++) {
|
||||
s->tx_desc_addr[i] = s->regs[GEM_TXQBASE];
|
||||
}
|
||||
}
|
||||
if (gem_can_receive(qemu_get_queue(s->nic))) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
|
@ -1150,10 +1370,16 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_RXQBASE:
|
||||
s->rx_desc_addr = val;
|
||||
s->rx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_RECEIVE_Q1_PTR ... GEM_RECEIVE_Q15_PTR:
|
||||
s->rx_desc_addr[offset - GEM_RECEIVE_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_TXQBASE:
|
||||
s->tx_desc_addr = val;
|
||||
s->tx_desc_addr[0] = val;
|
||||
break;
|
||||
case GEM_TRANSMIT_Q1_PTR ... GEM_TRANSMIT_Q15_PTR:
|
||||
s->tx_desc_addr[offset - GEM_TRANSMIT_Q1_PTR + 1] = val;
|
||||
break;
|
||||
case GEM_RXSTATUS:
|
||||
gem_update_int_status(s);
|
||||
|
@ -1162,10 +1388,26 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
|
|||
s->regs[GEM_IMR] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE:
|
||||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_ENABLE ... GEM_INT_Q15_ENABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_ENABLE] &= ~val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_IDR:
|
||||
s->regs[GEM_IMR] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q1_DISABLE ... GEM_INT_Q7_DISABLE:
|
||||
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_INT_Q8_DISABLE ... GEM_INT_Q15_DISABLE:
|
||||
s->regs[GEM_INT_Q8_MASK + offset - GEM_INT_Q8_DISABLE] |= val;
|
||||
gem_update_int_status(s);
|
||||
break;
|
||||
case GEM_SPADDR1LO:
|
||||
case GEM_SPADDR2LO:
|
||||
case GEM_SPADDR3LO:
|
||||
|
@ -1202,8 +1444,11 @@ static const MemoryRegionOps gem_ops = {
|
|||
|
||||
static void gem_set_link(NetClientState *nc)
|
||||
{
|
||||
CadenceGEMState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
DB_PRINT("\n");
|
||||
phy_update_link(qemu_get_nic_opaque(nc));
|
||||
phy_update_link(s);
|
||||
gem_update_int_status(s);
|
||||
}
|
||||
|
||||
static NetClientInfo net_gem_info = {
|
||||
|
@ -1214,36 +1459,62 @@ static NetClientInfo net_gem_info = {
|
|||
.link_status_changed = gem_set_link,
|
||||
};
|
||||
|
||||
static int gem_init(SysBusDevice *sbd)
|
||||
static void gem_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(sbd);
|
||||
CadenceGEMState *s = CADENCE_GEM(dev);
|
||||
int i;
|
||||
|
||||
if (s->num_priority_queues == 0 ||
|
||||
s->num_priority_queues > MAX_PRIORITY_QUEUES) {
|
||||
error_setg(errp, "Invalid num-priority-queues value: %" PRIx8,
|
||||
s->num_priority_queues);
|
||||
return;
|
||||
} else if (s->num_type1_screeners > MAX_TYPE1_SCREENERS) {
|
||||
error_setg(errp, "Invalid num-type1-screeners value: %" PRIx8,
|
||||
s->num_type1_screeners);
|
||||
return;
|
||||
} else if (s->num_type2_screeners > MAX_TYPE2_SCREENERS) {
|
||||
error_setg(errp, "Invalid num-type2-screeners value: %" PRIx8,
|
||||
s->num_type2_screeners);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < s->num_priority_queues; ++i) {
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void gem_init(Object *obj)
|
||||
{
|
||||
CadenceGEMState *s = CADENCE_GEM(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
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;
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_cadence_gem = {
|
||||
.name = "cadence_gem",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 4,
|
||||
.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_UINT32_ARRAY(rx_desc_addr, CadenceGEMState,
|
||||
MAX_PRIORITY_QUEUES),
|
||||
VMSTATE_UINT32_ARRAY(tx_desc_addr, CadenceGEMState,
|
||||
MAX_PRIORITY_QUEUES),
|
||||
VMSTATE_BOOL_ARRAY(sar_active, CadenceGEMState, 4),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
|
@ -1251,15 +1522,20 @@ static const VMStateDescription vmstate_cadence_gem = {
|
|||
|
||||
static Property gem_properties[] = {
|
||||
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
|
||||
DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
|
||||
num_priority_queues, 1),
|
||||
DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState,
|
||||
num_type1_screeners, 4),
|
||||
DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState,
|
||||
num_type2_screeners, 4),
|
||||
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->realize = gem_realize;
|
||||
dc->props = gem_properties;
|
||||
dc->vmsd = &vmstate_cadence_gem;
|
||||
dc->reset = gem_reset;
|
||||
|
@ -1269,6 +1545,7 @@ static const TypeInfo gem_info = {
|
|||
.name = TYPE_CADENCE_GEM,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(CadenceGEMState),
|
||||
.instance_init = gem_init,
|
||||
.class_init = gem_class_init,
|
||||
};
|
||||
|
||||
|
|
|
@ -387,7 +387,7 @@ static void etsec_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
|
||||
etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
|
||||
etsec->ptimer = ptimer_init(etsec->bh);
|
||||
etsec->ptimer = ptimer_init(etsec->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(etsec->ptimer, 100);
|
||||
}
|
||||
|
||||
|
|
|
@ -1345,7 +1345,7 @@ static int lan9118_init1(SysBusDevice *sbd)
|
|||
s->txp = &s->tx_packet;
|
||||
|
||||
bh = qemu_bh_new(lan9118_tick, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(s->timer, 10000);
|
||||
ptimer_set_limit(s->timer, 0xffff, 1);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
|
|||
#endif
|
||||
|
||||
typedef enum {
|
||||
SSI_SD_CMD,
|
||||
SSI_SD_CMD = 0,
|
||||
SSI_SD_CMDARG,
|
||||
SSI_SD_RESPONSE,
|
||||
SSI_SD_DATA_START,
|
||||
|
@ -40,13 +40,13 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
SSISlave ssidev;
|
||||
ssi_sd_mode mode;
|
||||
uint32_t mode;
|
||||
int cmd;
|
||||
uint8_t cmdarg[4];
|
||||
uint8_t response[5];
|
||||
int arglen;
|
||||
int response_pos;
|
||||
int stopping;
|
||||
int32_t arglen;
|
||||
int32_t response_pos;
|
||||
int32_t stopping;
|
||||
SDState *sd;
|
||||
} ssi_sd_state;
|
||||
|
||||
|
@ -198,61 +198,46 @@ static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
|
|||
return 0xff;
|
||||
}
|
||||
|
||||
static void ssi_sd_save(QEMUFile *f, void *opaque)
|
||||
static int ssi_sd_post_load(void *opaque, int version_id)
|
||||
{
|
||||
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)
|
||||
if (s->mode > SSI_SD_DATA_READ) {
|
||||
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 const VMStateDescription vmstate_ssi_sd = {
|
||||
.name = "ssi_sd",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.post_load = ssi_sd_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT32(mode, ssi_sd_state),
|
||||
VMSTATE_INT32(cmd, ssi_sd_state),
|
||||
VMSTATE_UINT8_ARRAY(cmdarg, ssi_sd_state, 4),
|
||||
VMSTATE_UINT8_ARRAY(response, ssi_sd_state, 5),
|
||||
VMSTATE_INT32(arglen, ssi_sd_state),
|
||||
VMSTATE_INT32(response_pos, ssi_sd_state),
|
||||
VMSTATE_INT32(stopping, ssi_sd_state),
|
||||
VMSTATE_SSI_SLAVE(ssidev, ssi_sd_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void ssi_sd_realize(SSISlave *d, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(d);
|
||||
ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
|
||||
DriveInfo *dinfo;
|
||||
|
||||
|
@ -264,16 +249,17 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
|
|||
error_setg(errp, "Device initialization failed.");
|
||||
return;
|
||||
}
|
||||
register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
|
||||
}
|
||||
|
||||
static void ssi_sd_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
|
||||
|
||||
k->realize = ssi_sd_realize;
|
||||
k->transfer = ssi_sd_transfer;
|
||||
k->cs_polarity = SSI_CS_LOW;
|
||||
dc->vmsd = &vmstate_ssi_sd;
|
||||
}
|
||||
|
||||
static const TypeInfo ssi_sd_info = {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx_spi_reg_name(uint32_t reg)
|
||||
static const char *imx_spi_reg_name(uint32_t reg)
|
||||
{
|
||||
static char unknown[20];
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ static void a10_pit_init(Object *obj)
|
|||
tc->container = s;
|
||||
tc->index = i;
|
||||
bh[i] = qemu_bh_new(a10_pit_timer_cb, tc);
|
||||
s->timer[i] = ptimer_init(bh[i]);
|
||||
s->timer[i] = ptimer_init(bh[i], PTIMER_POLICY_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
|
|||
s->control = TIMER_CTRL_IE;
|
||||
|
||||
bh = qemu_bh_new(arm_timer_tick, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
vmstate_register(NULL, -1, &vmstate_arm_timer, s);
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ static void digic_timer_init(Object *obj)
|
|||
{
|
||||
DigicTimerState *s = DIGIC_TIMER(obj);
|
||||
|
||||
s->ptimer = ptimer_init(NULL);
|
||||
s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
/*
|
||||
* FIXME: there is no documentation on Digic timer
|
||||
|
|
|
@ -322,9 +322,9 @@ static int etraxfs_timer_init(SysBusDevice *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);
|
||||
t->ptimer_t0 = ptimer_init(t->bh_t0, PTIMER_POLICY_DEFAULT);
|
||||
t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT);
|
||||
t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
sysbus_init_irq(dev, &t->irq);
|
||||
sysbus_init_irq(dev, &t->nmi);
|
||||
|
|
|
@ -1431,15 +1431,16 @@ static void exynos4210_mct_init(Object *obj)
|
|||
|
||||
/* Global timer */
|
||||
bh[0] = qemu_bh_new(exynos4210_gfrc_event, s);
|
||||
s->g_timer.ptimer_frc = ptimer_init(bh[0]);
|
||||
s->g_timer.ptimer_frc = ptimer_init(bh[0], PTIMER_POLICY_DEFAULT);
|
||||
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].tick_timer.ptimer_tick =
|
||||
ptimer_init(bh[0], PTIMER_POLICY_DEFAULT);
|
||||
s->l_timer[i].ptimer_frc = ptimer_init(bh[1], PTIMER_POLICY_DEFAULT);
|
||||
s->l_timer[i].id = i;
|
||||
}
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@ static void exynos4210_pwm_init(Object *obj)
|
|||
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].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
s->timer[i].id = i;
|
||||
s->timer[i].parent = s;
|
||||
}
|
||||
|
|
|
@ -555,12 +555,12 @@ static void exynos4210_rtc_init(Object *obj)
|
|||
QEMUBH *bh;
|
||||
|
||||
bh = qemu_bh_new(exynos4210_rtc_tick, s);
|
||||
s->ptimer = ptimer_init(bh);
|
||||
s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
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);
|
||||
s->ptimer_1Hz = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
|
||||
|
||||
sysbus_init_irq(dev, &s->alm_irq);
|
||||
|
|
|
@ -363,7 +363,7 @@ static int grlib_gptimer_init(SysBusDevice *dev)
|
|||
|
||||
timer->unit = unit;
|
||||
timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
|
||||
timer->ptimer = ptimer_init(timer->bh);
|
||||
timer->ptimer = ptimer_init(timer->bh, PTIMER_POLICY_DEFAULT);
|
||||
timer->id = i;
|
||||
|
||||
/* One IRQ line for each timer */
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx_epit_reg_name(uint32_t reg)
|
||||
static const char *imx_epit_reg_name(uint32_t reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0:
|
||||
|
@ -314,10 +314,10 @@ static void imx_epit_realize(DeviceState *dev, Error **errp)
|
|||
0x00001000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
s->timer_reload = ptimer_init(NULL);
|
||||
s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
bh = qemu_bh_new(imx_epit_cmp, s);
|
||||
s->timer_cmp = ptimer_init(bh);
|
||||
s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
}
|
||||
|
||||
static void imx_epit_class_init(ObjectClass *klass, void *data)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static char const *imx_gpt_reg_name(uint32_t reg)
|
||||
static const char *imx_gpt_reg_name(uint32_t reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case 0:
|
||||
|
@ -461,7 +461,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
bh = qemu_bh_new(imx_gpt_timeout, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
}
|
||||
|
||||
static void imx_gpt_class_init(ObjectClass *klass, void *data)
|
||||
|
|
|
@ -184,7 +184,7 @@ static void lm32_timer_init(Object *obj)
|
|||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
s->bh = qemu_bh_new(timer_hit, s);
|
||||
s->ptimer = ptimer_init(s->bh);
|
||||
s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &timer_ops, s,
|
||||
"timer", R_MAX * 4);
|
||||
|
|
|
@ -281,8 +281,8 @@ static void milkymist_sysctl_init(Object *obj)
|
|||
|
||||
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);
|
||||
s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT);
|
||||
s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
memory_region_init_io(&s->regs_region, obj, &sysctl_mmio_ops, s,
|
||||
"milkymist-sysctl", R_MAX * 4);
|
||||
|
|
|
@ -125,7 +125,7 @@ static int puv3_ost_init(SysBusDevice *dev)
|
|||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
s->bh = qemu_bh_new(puv3_ost_tick, s);
|
||||
s->ptimer = ptimer_init(s->bh);
|
||||
s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost",
|
||||
|
|
|
@ -203,7 +203,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
|
|||
s->irq = irq;
|
||||
|
||||
bh = qemu_bh_new(sh_timer_tick, s);
|
||||
s->timer = ptimer_init(bh);
|
||||
s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
|
||||
sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
|
||||
sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
|
||||
|
|
|
@ -389,7 +389,7 @@ static int slavio_timer_init1(SysBusDevice *dev)
|
|||
tc->timer_index = i;
|
||||
|
||||
bh = qemu_bh_new(slavio_timer_irq, tc);
|
||||
s->cputimer[i].timer = ptimer_init(bh);
|
||||
s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
|
||||
|
||||
size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
|
||||
|
|
|
@ -218,7 +218,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp)
|
|||
xt->parent = t;
|
||||
xt->nr = i;
|
||||
xt->bh = qemu_bh_new(timer_hit, xt);
|
||||
xt->ptimer = ptimer_init(xt->bh);
|
||||
xt->ptimer = ptimer_init(xt->bh, PTIMER_POLICY_DEFAULT);
|
||||
ptimer_set_freq(xt->ptimer, t->freq_hz);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ASPEED SoC family
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ASPEED_SOC_H
|
||||
#define ASPEED_SOC_H
|
||||
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/intc/aspeed_vic.h"
|
||||
#include "hw/misc/aspeed_scu.h"
|
||||
#include "hw/misc/aspeed_sdmc.h"
|
||||
#include "hw/timer/aspeed_timer.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
#include "hw/ssi/aspeed_smc.h"
|
||||
|
||||
typedef struct AspeedSoCState {
|
||||
/*< private >*/
|
||||
DeviceState parent;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion iomem;
|
||||
AspeedVICState vic;
|
||||
AspeedTimerCtrlState timerctrl;
|
||||
AspeedI2CState i2c;
|
||||
AspeedSCUState scu;
|
||||
AspeedSMCState smc;
|
||||
AspeedSMCState spi;
|
||||
AspeedSDMCState sdmc;
|
||||
} AspeedSoCState;
|
||||
|
||||
#define TYPE_ASPEED_SOC "aspeed-soc"
|
||||
#define ASPEED_SOC(obj) OBJECT_CHECK(AspeedSoCState, (obj), TYPE_ASPEED_SOC)
|
||||
|
||||
typedef struct AspeedSoCInfo {
|
||||
const char *name;
|
||||
const char *cpu_model;
|
||||
uint32_t silicon_rev;
|
||||
hwaddr sdram_base;
|
||||
} AspeedSoCInfo;
|
||||
|
||||
typedef struct AspeedSoCClass {
|
||||
DeviceClass parent_class;
|
||||
AspeedSoCInfo *info;
|
||||
} AspeedSoCClass;
|
||||
|
||||
#define ASPEED_SOC_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(AspeedSoCClass, (klass), TYPE_ASPEED_SOC)
|
||||
#define ASPEED_SOC_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(AspeedSoCClass, (obj), TYPE_ASPEED_SOC)
|
||||
|
||||
#endif /* ASPEED_SOC_H */
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* ASPEED AST2400 SoC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef AST2400_H
|
||||
#define AST2400_H
|
||||
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/intc/aspeed_vic.h"
|
||||
#include "hw/misc/aspeed_scu.h"
|
||||
#include "hw/misc/aspeed_sdmc.h"
|
||||
#include "hw/timer/aspeed_timer.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
#include "hw/ssi/aspeed_smc.h"
|
||||
|
||||
typedef struct AST2400State {
|
||||
/*< private >*/
|
||||
DeviceState parent;
|
||||
|
||||
/*< public >*/
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion iomem;
|
||||
AspeedVICState vic;
|
||||
AspeedTimerCtrlState timerctrl;
|
||||
AspeedI2CState i2c;
|
||||
AspeedSCUState scu;
|
||||
AspeedSMCState smc;
|
||||
AspeedSMCState spi;
|
||||
AspeedSDMCState sdmc;
|
||||
} AST2400State;
|
||||
|
||||
#define TYPE_AST2400 "ast2400"
|
||||
#define AST2400(obj) OBJECT_CHECK(AST2400State, (obj), TYPE_AST2400)
|
||||
|
||||
#define AST2400_SDRAM_BASE 0x40000000
|
||||
|
||||
#endif /* AST2400_H */
|
|
@ -34,7 +34,7 @@
|
|||
#define XLNX_ZYNQ_DEVCFG(obj) \
|
||||
OBJECT_CHECK(XlnxZynqDevcfg, (obj), TYPE_XLNX_ZYNQ_DEVCFG)
|
||||
|
||||
#define XLNX_ZYNQ_DEVCFG_R_MAX 0x118
|
||||
#define XLNX_ZYNQ_DEVCFG_R_MAX (0x100 / 4)
|
||||
|
||||
#define XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN 10
|
||||
|
||||
|
|
|
@ -263,7 +263,8 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
|||
void *translate_opaque,
|
||||
int must_swab, uint64_t *pentry,
|
||||
uint64_t *lowaddr, uint64_t *highaddr,
|
||||
int elf_machine, int clear_lsb, int data_swab)
|
||||
int elf_machine, int clear_lsb, int data_swab,
|
||||
AddressSpace *as)
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
struct elf_phdr *phdr = NULL, *ph;
|
||||
|
@ -280,6 +281,11 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
|||
glue(bswap_ehdr, SZ)(&ehdr);
|
||||
}
|
||||
|
||||
if (elf_machine <= EM_NONE) {
|
||||
/* The caller didn't specify an ARCH, we can figure it out */
|
||||
elf_machine = ehdr.e_machine;
|
||||
}
|
||||
|
||||
switch (elf_machine) {
|
||||
case EM_PPC64:
|
||||
if (ehdr.e_machine != EM_PPC64) {
|
||||
|
@ -400,7 +406,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
|||
snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
|
||||
|
||||
/* rom_add_elf_program() seize the ownership of 'data' */
|
||||
rom_add_elf_program(label, data, file_size, mem_size, addr);
|
||||
rom_add_elf_program(label, data, file_size, mem_size, addr, as);
|
||||
|
||||
total_size += mem_size;
|
||||
if (addr < low)
|
||||
|
|
|
@ -14,8 +14,28 @@
|
|||
int get_image_size(const char *filename);
|
||||
int load_image(const char *filename, uint8_t *addr); /* deprecated */
|
||||
ssize_t load_image_size(const char *filename, void *addr, size_t size);
|
||||
|
||||
/**load_image_targphys_as:
|
||||
* @filename: Path to the image file
|
||||
* @addr: Address to load the image to
|
||||
* @max_sz: The maximum size of the image to load
|
||||
* @as: The AddressSpace to load the ELF to. The value of address_space_memory
|
||||
* is used if nothing is supplied here.
|
||||
*
|
||||
* Load a fixed image into memory.
|
||||
*
|
||||
* Returns the size of the loaded image on success, -1 otherwise.
|
||||
*/
|
||||
int load_image_targphys_as(const char *filename,
|
||||
hwaddr addr, uint64_t max_sz, AddressSpace *as);
|
||||
|
||||
/** load_image_targphys:
|
||||
* Same as load_image_targphys_as(), but doesn't allow the caller to specify
|
||||
* an AddressSpace.
|
||||
*/
|
||||
int load_image_targphys(const char *filename, hwaddr,
|
||||
uint64_t max_sz);
|
||||
|
||||
/**
|
||||
* load_image_mr: load an image into a memory region
|
||||
* @filename: Path to the image file
|
||||
|
@ -45,7 +65,7 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
|
|||
#define ELF_LOAD_WRONG_ENDIAN -4
|
||||
const char *load_elf_strerror(int error);
|
||||
|
||||
/** load_elf:
|
||||
/** load_elf_as:
|
||||
* @filename: Path of ELF file
|
||||
* @translate_fn: optional function to translate load addresses
|
||||
* @translate_opaque: opaque data passed to @translate_fn
|
||||
|
@ -59,6 +79,8 @@ const char *load_elf_strerror(int error);
|
|||
* @data_swab: Set to order of byte swapping for data. 0 for no swap, 1
|
||||
* for swapping bytes within halfwords, 2 for bytes within
|
||||
* words and 3 for within doublewords.
|
||||
* @as: The AddressSpace to load the ELF to. The value of address_space_memory
|
||||
* is used if nothing is supplied here.
|
||||
*
|
||||
* Load an ELF file's contents to the emulated system's address space.
|
||||
* Clients may optionally specify a callback to perform address
|
||||
|
@ -68,8 +90,19 @@ const char *load_elf_strerror(int error);
|
|||
* load will fail if the target ELF does not match. Some architectures
|
||||
* have some architecture-specific behaviours that come into effect when
|
||||
* their particular values for @elf_machine are set.
|
||||
* If @elf_machine is EM_NONE then the machine type will be read from the
|
||||
* ELF header and no checks will be carried out against the machine type.
|
||||
*/
|
||||
int load_elf_as(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, AddressSpace *as);
|
||||
|
||||
/** load_elf:
|
||||
* Same as load_elf_as(), but doesn't allow the caller to specify an
|
||||
* AddressSpace.
|
||||
*/
|
||||
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,
|
||||
|
@ -89,6 +122,30 @@ void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp);
|
|||
|
||||
int load_aout(const char *filename, hwaddr addr, int max_sz,
|
||||
int bswap_needed, hwaddr target_page_size);
|
||||
|
||||
/** load_uimage_as:
|
||||
* @filename: Path of uimage file
|
||||
* @ep: Populated with program entry point. Ignored if NULL.
|
||||
* @loadaddr: Populated with the load address. Ignored if NULL.
|
||||
* @is_linux: Is set to true if the image loaded is Linux. Ignored if NULL.
|
||||
* @translate_fn: optional function to translate load addresses
|
||||
* @translate_opaque: opaque data passed to @translate_fn
|
||||
* @as: The AddressSpace to load the ELF to. The value of address_space_memory
|
||||
* is used if nothing is supplied here.
|
||||
*
|
||||
* Loads a u-boot image into memory.
|
||||
*
|
||||
* Returns the size of the loaded image on success, -1 otherwise.
|
||||
*/
|
||||
int load_uimage_as(const char *filename, hwaddr *ep,
|
||||
hwaddr *loadaddr, int *is_linux,
|
||||
uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, AddressSpace *as);
|
||||
|
||||
/** load_uimage:
|
||||
* Same as load_uimage_as(), but doesn't allow the caller to specify an
|
||||
* AddressSpace.
|
||||
*/
|
||||
int load_uimage(const char *filename, hwaddr *ep,
|
||||
hwaddr *loadaddr, int *is_linux,
|
||||
uint64_t (*translate_fn)(void *, uint64_t),
|
||||
|
@ -118,14 +175,14 @@ extern bool rom_file_has_mr;
|
|||
|
||||
int rom_add_file(const char *file, const char *fw_dir,
|
||||
hwaddr addr, int32_t bootindex,
|
||||
bool option_rom, MemoryRegion *mr);
|
||||
bool option_rom, MemoryRegion *mr, AddressSpace *as);
|
||||
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);
|
||||
int rom_add_elf_program(const char *name, void *data, size_t datasize,
|
||||
size_t romsize, hwaddr addr);
|
||||
size_t romsize, hwaddr addr, AddressSpace *as);
|
||||
int rom_check_and_register_reset(void);
|
||||
void rom_set_fw(FWCfgState *f);
|
||||
void rom_set_order_override(int order);
|
||||
|
@ -135,11 +192,17 @@ void *rom_ptr(hwaddr addr);
|
|||
void hmp_info_roms(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#define rom_add_file_fixed(_f, _a, _i) \
|
||||
rom_add_file(_f, NULL, _a, _i, false, NULL)
|
||||
rom_add_file(_f, NULL, _a, _i, false, NULL, NULL)
|
||||
#define rom_add_blob_fixed(_f, _b, _l, _a) \
|
||||
rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL)
|
||||
#define rom_add_file_mr(_f, _mr, _i) \
|
||||
rom_add_file(_f, NULL, 0, _i, false, _mr)
|
||||
rom_add_file(_f, NULL, 0, _i, false, _mr, NULL)
|
||||
#define rom_add_file_as(_f, _as, _i) \
|
||||
rom_add_file(_f, NULL, 0, _i, false, NULL, _as)
|
||||
#define rom_add_file_fixed_as(_f, _a, _i, _as) \
|
||||
rom_add_file(_f, NULL, _a, _i, false, NULL, _as)
|
||||
#define rom_add_blob_fixed_as(_f, _b, _l, _a, _as) \
|
||||
rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, _as)
|
||||
|
||||
#define PC_ROM_MIN_VGA 0xc0000
|
||||
#define PC_ROM_MIN_OPTION 0xc8000
|
||||
|
|
|
@ -33,7 +33,200 @@ typedef struct AspeedSCUState {
|
|||
|
||||
#define AST2400_A0_SILICON_REV 0x02000303U
|
||||
#define AST2500_A0_SILICON_REV 0x04000303U
|
||||
#define AST2500_A1_SILICON_REV 0x04010303U
|
||||
|
||||
extern bool is_supported_silicon_rev(uint32_t silicon_rev);
|
||||
|
||||
/*
|
||||
* Extracted from Aspeed SDK v00.03.21. Fixes and extra definitions
|
||||
* were added.
|
||||
*
|
||||
* Original header file :
|
||||
* arch/arm/mach-aspeed/include/mach/regs-scu.h
|
||||
*
|
||||
* Copyright (C) 2012-2020 ASPEED Technology 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.
|
||||
*
|
||||
* History :
|
||||
* 1. 2012/12/29 Ryan Chen Create
|
||||
*/
|
||||
|
||||
/* Hardware Strapping Register definition (for Aspeed AST2400 SOC)
|
||||
*
|
||||
* 31:29 Software defined strapping registers
|
||||
* 28:27 DRAM size setting (for VGA driver use)
|
||||
* 26:24 DRAM configuration setting
|
||||
* 23 Enable 25 MHz reference clock input
|
||||
* 22 Enable GPIOE pass-through mode
|
||||
* 21 Enable GPIOD pass-through mode
|
||||
* 20 Disable LPC to decode SuperIO 0x2E/0x4E address
|
||||
* 19 Disable ACPI function
|
||||
* 23,18 Clock source selection
|
||||
* 17 Enable BMC 2nd boot watchdog timer
|
||||
* 16 SuperIO configuration address selection
|
||||
* 15 VGA Class Code selection
|
||||
* 14 Enable LPC dedicated reset pin function
|
||||
* 13:12 SPI mode selection
|
||||
* 11:10 CPU/AHB clock frequency ratio selection
|
||||
* 9:8 H-PLL default clock frequency selection
|
||||
* 7 Define MAC#2 interface
|
||||
* 6 Define MAC#1 interface
|
||||
* 5 Enable VGA BIOS ROM
|
||||
* 4 Boot flash memory extended option
|
||||
* 3:2 VGA memory size selection
|
||||
* 1:0 BMC CPU boot code selection
|
||||
*/
|
||||
#define SCU_AST2400_HW_STRAP_SW_DEFINE(x) ((x) << 29)
|
||||
#define SCU_AST2400_HW_STRAP_SW_DEFINE_MASK (0x7 << 29)
|
||||
|
||||
#define SCU_AST2400_HW_STRAP_DRAM_SIZE(x) ((x) << 27)
|
||||
#define SCU_AST2400_HW_STRAP_DRAM_SIZE_MASK (0x3 << 27)
|
||||
#define DRAM_SIZE_64MB 0
|
||||
#define DRAM_SIZE_128MB 1
|
||||
#define DRAM_SIZE_256MB 2
|
||||
#define DRAM_SIZE_512MB 3
|
||||
|
||||
#define SCU_AST2400_HW_STRAP_DRAM_CONFIG(x) ((x) << 24)
|
||||
#define SCU_AST2400_HW_STRAP_DRAM_CONFIG_MASK (0x7 << 24)
|
||||
|
||||
#define SCU_HW_STRAP_GPIOE_PT_EN (0x1 << 22)
|
||||
#define SCU_HW_STRAP_GPIOD_PT_EN (0x1 << 21)
|
||||
#define SCU_HW_STRAP_LPC_DEC_SUPER_IO (0x1 << 20)
|
||||
#define SCU_AST2400_HW_STRAP_ACPI_DIS (0x1 << 19)
|
||||
|
||||
/* bit 23, 18 [1,0] */
|
||||
#define SCU_AST2400_HW_STRAP_SET_CLK_SOURCE(x) (((((x) & 0x3) >> 1) << 23) \
|
||||
| (((x) & 0x1) << 18))
|
||||
#define SCU_AST2400_HW_STRAP_GET_CLK_SOURCE(x) (((((x) >> 23) & 0x1) << 1) \
|
||||
| (((x) >> 18) & 0x1))
|
||||
#define SCU_AST2400_HW_STRAP_CLK_SOURCE_MASK ((0x1 << 23) | (0x1 << 18))
|
||||
#define AST2400_CLK_25M_IN (0x1 << 23)
|
||||
#define AST2400_CLK_24M_IN 0
|
||||
#define AST2400_CLK_48M_IN 1
|
||||
#define AST2400_CLK_25M_IN_24M_USB_CKI 2
|
||||
#define AST2400_CLK_25M_IN_48M_USB_CKI 3
|
||||
|
||||
#define SCU_HW_STRAP_2ND_BOOT_WDT (0x1 << 17)
|
||||
#define SCU_HW_STRAP_SUPER_IO_CONFIG (0x1 << 16)
|
||||
#define SCU_HW_STRAP_VGA_CLASS_CODE (0x1 << 15)
|
||||
#define SCU_HW_STRAP_LPC_RESET_PIN (0x1 << 14)
|
||||
|
||||
#define SCU_HW_STRAP_SPI_MODE(x) ((x) << 12)
|
||||
#define SCU_HW_STRAP_SPI_MODE_MASK (0x3 << 12)
|
||||
#define SCU_HW_STRAP_SPI_DIS 0
|
||||
#define SCU_HW_STRAP_SPI_MASTER 1
|
||||
#define SCU_HW_STRAP_SPI_M_S_EN 2
|
||||
#define SCU_HW_STRAP_SPI_PASS_THROUGH 3
|
||||
|
||||
#define SCU_AST2400_HW_STRAP_SET_CPU_AHB_RATIO(x) ((x) << 10)
|
||||
#define SCU_AST2400_HW_STRAP_GET_CPU_AHB_RATIO(x) (((x) >> 10) & 3)
|
||||
#define SCU_AST2400_HW_STRAP_CPU_AHB_RATIO_MASK (0x3 << 10)
|
||||
#define AST2400_CPU_AHB_RATIO_1_1 0
|
||||
#define AST2400_CPU_AHB_RATIO_2_1 1
|
||||
#define AST2400_CPU_AHB_RATIO_4_1 2
|
||||
#define AST2400_CPU_AHB_RATIO_3_1 3
|
||||
|
||||
#define SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(x) (((x) >> 8) & 0x3)
|
||||
#define SCU_AST2400_HW_STRAP_H_PLL_CLK_MASK (0x3 << 8)
|
||||
#define AST2400_CPU_384MHZ 0
|
||||
#define AST2400_CPU_360MHZ 1
|
||||
#define AST2400_CPU_336MHZ 2
|
||||
#define AST2400_CPU_408MHZ 3
|
||||
|
||||
#define SCU_HW_STRAP_MAC1_RGMII (0x1 << 7)
|
||||
#define SCU_HW_STRAP_MAC0_RGMII (0x1 << 6)
|
||||
#define SCU_HW_STRAP_VGA_BIOS_ROM (0x1 << 5)
|
||||
#define SCU_HW_STRAP_SPI_WIDTH (0x1 << 4)
|
||||
|
||||
#define SCU_HW_STRAP_VGA_SIZE_GET(x) (((x) >> 2) & 0x3)
|
||||
#define SCU_HW_STRAP_VGA_MASK (0x3 << 2)
|
||||
#define SCU_HW_STRAP_VGA_SIZE_SET(x) ((x) << 2)
|
||||
#define VGA_8M_DRAM 0
|
||||
#define VGA_16M_DRAM 1
|
||||
#define VGA_32M_DRAM 2
|
||||
#define VGA_64M_DRAM 3
|
||||
|
||||
#define SCU_AST2400_HW_STRAP_BOOT_MODE(x) (x)
|
||||
#define AST2400_NOR_BOOT 0
|
||||
#define AST2400_NAND_BOOT 1
|
||||
#define AST2400_SPI_BOOT 2
|
||||
#define AST2400_DIS_BOOT 3
|
||||
|
||||
/*
|
||||
* Hardware strapping register definition (for Aspeed AST2500 SoC and
|
||||
* higher)
|
||||
*
|
||||
* 31 Enable SPI Flash Strap Auto Fetch Mode
|
||||
* 30 Enable GPIO Strap Mode
|
||||
* 29 Select UART Debug Port
|
||||
* 28 Reserved (1)
|
||||
* 27 Enable fast reset mode for ARM ICE debugger
|
||||
* 26 Enable eSPI flash mode
|
||||
* 25 Enable eSPI mode
|
||||
* 24 Select DDR4 SDRAM
|
||||
* 23 Select 25 MHz reference clock input mode
|
||||
* 22 Enable GPIOE pass-through mode
|
||||
* 21 Enable GPIOD pass-through mode
|
||||
* 20 Disable LPC to decode SuperIO 0x2E/0x4E address
|
||||
* 19 Enable ACPI function
|
||||
* 18 Select USBCKI input frequency
|
||||
* 17 Enable BMC 2nd boot watchdog timer
|
||||
* 16 SuperIO configuration address selection
|
||||
* 15 VGA Class Code selection
|
||||
* 14 Select dedicated LPC reset input
|
||||
* 13:12 SPI mode selection
|
||||
* 11:9 AXI/AHB clock frequency ratio selection
|
||||
* 8 Reserved (0)
|
||||
* 7 Define MAC#2 interface
|
||||
* 6 Define MAC#1 interface
|
||||
* 5 Enable dedicated VGA BIOS ROM
|
||||
* 4 Reserved (0)
|
||||
* 3:2 VGA memory size selection
|
||||
* 1 Reserved (1)
|
||||
* 0 Disable CPU boot
|
||||
*/
|
||||
#define SCU_AST2500_HW_STRAP_SPI_AUTOFETCH_ENABLE (0x1 << 31)
|
||||
#define SCU_AST2500_HW_STRAP_GPIO_STRAP_ENABLE (0x1 << 30)
|
||||
#define SCU_AST2500_HW_STRAP_UART_DEBUG (0x1 << 29)
|
||||
#define UART_DEBUG_UART1 0
|
||||
#define UART_DEBUG_UART5 1
|
||||
#define SCU_AST2500_HW_STRAP_RESERVED28 (0x1 << 28)
|
||||
|
||||
#define SCU_AST2500_HW_STRAP_FAST_RESET_DBG (0x1 << 27)
|
||||
#define SCU_AST2500_HW_STRAP_ESPI_FLASH_ENABLE (0x1 << 26)
|
||||
#define SCU_AST2500_HW_STRAP_ESPI_ENABLE (0x1 << 25)
|
||||
#define SCU_AST2500_HW_STRAP_DDR4_ENABLE (0x1 << 24)
|
||||
|
||||
#define SCU_AST2500_HW_STRAP_ACPI_ENABLE (0x1 << 19)
|
||||
#define SCU_AST2500_HW_STRAP_USBCKI_FREQ (0x1 << 18)
|
||||
#define USBCKI_FREQ_24MHZ 0
|
||||
#define USBCKI_FREQ_28MHZ 1
|
||||
|
||||
#define SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(x) ((x) << 9)
|
||||
#define SCU_AST2500_HW_STRAP_GET_AXI_AHB_RATIO(x) (((x) >> 9) & 7)
|
||||
#define SCU_AST2500_HW_STRAP_CPU_AXI_RATIO_MASK (0x7 << 9)
|
||||
#define AXI_AHB_RATIO_UNDEFINED 0
|
||||
#define AXI_AHB_RATIO_2_1 1
|
||||
#define AXI_AHB_RATIO_3_1 2
|
||||
#define AXI_AHB_RATIO_4_1 3
|
||||
#define AXI_AHB_RATIO_5_1 4
|
||||
#define AXI_AHB_RATIO_6_1 5
|
||||
#define AXI_AHB_RATIO_7_1 6
|
||||
#define AXI_AHB_RATIO_8_1 7
|
||||
|
||||
#define SCU_AST2500_HW_STRAP_RESERVED1 (0x1 << 1)
|
||||
#define SCU_AST2500_HW_STRAP_DIS_BOOT (0x1 << 0)
|
||||
|
||||
#define AST2500_HW_STRAP1_DEFAULTS ( \
|
||||
SCU_AST2500_HW_STRAP_RESERVED28 | \
|
||||
SCU_HW_STRAP_2ND_BOOT_WDT | \
|
||||
SCU_HW_STRAP_VGA_CLASS_CODE | \
|
||||
SCU_HW_STRAP_LPC_RESET_PIN | \
|
||||
SCU_AST2500_HW_STRAP_SET_AXI_AHB_RATIO(AXI_AHB_RATIO_2_1) | \
|
||||
SCU_HW_STRAP_VGA_SIZE_SET(VGA_16M_DRAM) | \
|
||||
SCU_AST2500_HW_STRAP_RESERVED1)
|
||||
|
||||
#endif /* ASPEED_SCU_H */
|
||||
|
|
|
@ -25,6 +25,8 @@ typedef struct AspeedSDMCState {
|
|||
|
||||
uint32_t regs[ASPEED_SDMC_NR_REGS];
|
||||
uint32_t silicon_rev;
|
||||
uint32_t ram_bits;
|
||||
uint64_t ram_size;
|
||||
|
||||
} AspeedSDMCState;
|
||||
|
||||
|
|
|
@ -30,7 +30,11 @@
|
|||
#include "net/net.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */
|
||||
#define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */
|
||||
|
||||
#define MAX_PRIORITY_QUEUES 8
|
||||
#define MAX_TYPE1_SCREENERS 16
|
||||
#define MAX_TYPE2_SCREENERS 16
|
||||
|
||||
typedef struct CadenceGEMState {
|
||||
/*< private >*/
|
||||
|
@ -40,7 +44,12 @@ typedef struct CadenceGEMState {
|
|||
MemoryRegion iomem;
|
||||
NICState *nic;
|
||||
NICConf conf;
|
||||
qemu_irq irq;
|
||||
qemu_irq irq[MAX_PRIORITY_QUEUES];
|
||||
|
||||
/* Static properties */
|
||||
uint8_t num_priority_queues;
|
||||
uint8_t num_type1_screeners;
|
||||
uint8_t num_type2_screeners;
|
||||
|
||||
/* GEM registers backing store */
|
||||
uint32_t regs[CADENCE_GEM_MAXREG];
|
||||
|
@ -59,12 +68,12 @@ typedef struct CadenceGEMState {
|
|||
uint8_t phy_loop; /* Are we in phy loopback? */
|
||||
|
||||
/* The current DMA descriptor pointers */
|
||||
uint32_t rx_desc_addr;
|
||||
uint32_t tx_desc_addr;
|
||||
uint32_t rx_desc_addr[MAX_PRIORITY_QUEUES];
|
||||
uint32_t tx_desc_addr[MAX_PRIORITY_QUEUES];
|
||||
|
||||
uint8_t can_rx_state; /* Debug only */
|
||||
|
||||
unsigned rx_desc[2];
|
||||
unsigned rx_desc[MAX_PRIORITY_QUEUES][2];
|
||||
|
||||
bool sar_active[4];
|
||||
} CadenceGEMState;
|
||||
|
|
|
@ -12,11 +12,34 @@
|
|||
#include "qemu/timer.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
/* The default ptimer policy retains backward compatibility with the legacy
|
||||
* timers. Custom policies are adjusting the default one. Consider providing
|
||||
* a correct policy for your timer.
|
||||
*
|
||||
* The rough edges of the default policy:
|
||||
* - Starting to run with a period = 0 emits error message and stops the
|
||||
* timer without a trigger.
|
||||
*
|
||||
* - Setting period to 0 of the running timer emits error message and
|
||||
* stops the timer without a trigger.
|
||||
*
|
||||
* - Starting to run with counter = 0 or setting it to "0" while timer
|
||||
* is running causes a trigger and reloads counter with a limit value.
|
||||
* If limit = 0, ptimer emits error message and stops the timer.
|
||||
*
|
||||
* - Counter value of the running timer is one less than the actual value.
|
||||
*
|
||||
* - Changing period/frequency of the running timer loses time elapsed
|
||||
* since the last period, effectively restarting the timer with a
|
||||
* counter = counter value at the moment of change (.i.e. one less).
|
||||
*/
|
||||
#define PTIMER_POLICY_DEFAULT 0
|
||||
|
||||
/* ptimer.c */
|
||||
typedef struct ptimer_state ptimer_state;
|
||||
typedef void (*ptimer_cb)(void *opaque);
|
||||
|
||||
ptimer_state *ptimer_init(QEMUBH *bh);
|
||||
ptimer_state *ptimer_init(QEMUBH *bh, uint8_t policy_mask);
|
||||
void ptimer_set_period(ptimer_state *s, int64_t period);
|
||||
void ptimer_set_freq(ptimer_state *s, uint32_t freq);
|
||||
uint64_t ptimer_get_limit(ptimer_state *s);
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
#include "migration/vmstate.h"
|
||||
|
||||
const VMStateDescription vmstate_dummy = {};
|
||||
const VMStateInfo vmstate_info_uint8;
|
||||
const VMStateInfo vmstate_info_uint32;
|
||||
const VMStateInfo vmstate_info_uint64;
|
||||
const VMStateInfo vmstate_info_int64;
|
||||
const VMStateInfo vmstate_info_timer;
|
||||
|
||||
int vmstate_register_with_alias_id(DeviceState *dev,
|
||||
int instance_id,
|
||||
|
|
|
@ -1129,6 +1129,51 @@ static const ARMCPRegInfo cortexa15_cp_reginfo[] = {
|
|||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
static void cortex_a7_initfn(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
||||
cpu->dtb_compatible = "arm,cortex-a7";
|
||||
set_feature(&cpu->env, ARM_FEATURE_V7);
|
||||
set_feature(&cpu->env, ARM_FEATURE_VFP4);
|
||||
set_feature(&cpu->env, ARM_FEATURE_NEON);
|
||||
set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_ARM_DIV);
|
||||
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
|
||||
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
|
||||
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
|
||||
set_feature(&cpu->env, ARM_FEATURE_LPAE);
|
||||
set_feature(&cpu->env, ARM_FEATURE_EL3);
|
||||
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
|
||||
cpu->midr = 0x410fc075;
|
||||
cpu->reset_fpsid = 0x41023075;
|
||||
cpu->mvfr0 = 0x10110222;
|
||||
cpu->mvfr1 = 0x11111111;
|
||||
cpu->ctr = 0x84448003;
|
||||
cpu->reset_sctlr = 0x00c50078;
|
||||
cpu->id_pfr0 = 0x00001131;
|
||||
cpu->id_pfr1 = 0x00011011;
|
||||
cpu->id_dfr0 = 0x02010555;
|
||||
cpu->pmceid0 = 0x00000000;
|
||||
cpu->pmceid1 = 0x00000000;
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
cpu->id_mmfr0 = 0x10101105;
|
||||
cpu->id_mmfr1 = 0x40000000;
|
||||
cpu->id_mmfr2 = 0x01240000;
|
||||
cpu->id_mmfr3 = 0x02102211;
|
||||
cpu->id_isar0 = 0x01101110;
|
||||
cpu->id_isar1 = 0x13112111;
|
||||
cpu->id_isar2 = 0x21232041;
|
||||
cpu->id_isar3 = 0x11112131;
|
||||
cpu->id_isar4 = 0x10011142;
|
||||
cpu->dbgdidr = 0x3515f005;
|
||||
cpu->clidr = 0x0a200023;
|
||||
cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
|
||||
cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
|
||||
define_arm_cp_regs(cpu, cortexa15_cp_reginfo); /* Same as A15 */
|
||||
}
|
||||
|
||||
static void cortex_a15_initfn(Object *obj)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(obj);
|
||||
|
@ -1385,6 +1430,7 @@ static const ARMCPUInfo arm_cpus[] = {
|
|||
{ .name = "cortex-m4", .initfn = cortex_m4_initfn,
|
||||
.class_init = arm_v7m_class_init },
|
||||
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },
|
||||
{ .name = "cortex-a7", .initfn = cortex_a7_initfn },
|
||||
{ .name = "cortex-a8", .initfn = cortex_a8_initfn },
|
||||
{ .name = "cortex-a9", .initfn = cortex_a9_initfn },
|
||||
{ .name = "cortex-a15", .initfn = cortex_a15_initfn },
|
||||
|
|
|
@ -296,6 +296,7 @@ check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
|
|||
check-qtest-s390x-y = tests/boot-serial-test$(EXESUF)
|
||||
|
||||
check-qtest-generic-y += tests/qom-test$(EXESUF)
|
||||
check-qtest-generic-y += tests/ptimer-test$(EXESUF)
|
||||
|
||||
qapi-schema += alternate-any.json
|
||||
qapi-schema += alternate-array.json
|
||||
|
@ -658,6 +659,7 @@ tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y)
|
|||
tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y)
|
||||
tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y)
|
||||
tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o
|
||||
tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o
|
||||
|
||||
tests/migration/stress$(EXESUF): tests/migration/stress.o
|
||||
$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ," LINK $(TARGET_DIR)$@")
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Stubs for the ptimer-test
|
||||
*
|
||||
* Author: Dmitry Osipenko <digetx@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
#include "ptimer-test.h"
|
||||
|
||||
struct QEMUBH {
|
||||
QEMUBHFunc *cb;
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
QEMUTimerListGroup main_loop_tlg;
|
||||
|
||||
int64_t ptimer_test_time_ns;
|
||||
|
||||
void timer_init_tl(QEMUTimer *ts,
|
||||
QEMUTimerList *timer_list, int scale,
|
||||
QEMUTimerCB *cb, void *opaque)
|
||||
{
|
||||
ts->timer_list = timer_list;
|
||||
ts->cb = cb;
|
||||
ts->opaque = opaque;
|
||||
ts->scale = scale;
|
||||
ts->expire_time = -1;
|
||||
}
|
||||
|
||||
void timer_mod(QEMUTimer *ts, int64_t expire_time)
|
||||
{
|
||||
QEMUTimerList *timer_list = ts->timer_list;
|
||||
QEMUTimer *t = &timer_list->active_timers;
|
||||
|
||||
while (t->next != NULL) {
|
||||
if (t->next == ts) {
|
||||
break;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
ts->expire_time = MAX(expire_time * ts->scale, 0);
|
||||
ts->next = NULL;
|
||||
t->next = ts;
|
||||
}
|
||||
|
||||
void timer_del(QEMUTimer *ts)
|
||||
{
|
||||
QEMUTimerList *timer_list = ts->timer_list;
|
||||
QEMUTimer *t = &timer_list->active_timers;
|
||||
|
||||
while (t->next != NULL) {
|
||||
if (t->next == ts) {
|
||||
t->next = ts->next;
|
||||
return;
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t qemu_clock_get_ns(QEMUClockType type)
|
||||
{
|
||||
return ptimer_test_time_ns;
|
||||
}
|
||||
|
||||
int64_t qemu_clock_deadline_ns_all(QEMUClockType type)
|
||||
{
|
||||
QEMUTimerList *timer_list = main_loop_tlg.tl[type];
|
||||
QEMUTimer *t = timer_list->active_timers.next;
|
||||
int64_t deadline = -1;
|
||||
|
||||
while (t != NULL) {
|
||||
if (deadline == -1) {
|
||||
deadline = t->expire_time;
|
||||
} else {
|
||||
deadline = MIN(deadline, t->expire_time);
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
return deadline;
|
||||
}
|
||||
|
||||
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh = g_new(QEMUBH, 1);
|
||||
|
||||
bh->cb = cb;
|
||||
bh->opaque = opaque;
|
||||
|
||||
return bh;
|
||||
}
|
||||
|
||||
void replay_bh_schedule_event(QEMUBH *bh)
|
||||
{
|
||||
bh->cb(bh->opaque);
|
||||
}
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
* QTest testcase for the ptimer
|
||||
*
|
||||
* Author: Dmitry Osipenko <digetx@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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "hw/ptimer.h"
|
||||
|
||||
#include "libqtest.h"
|
||||
#include "ptimer-test.h"
|
||||
|
||||
static bool triggered;
|
||||
|
||||
static void ptimer_trigger(void *opaque)
|
||||
{
|
||||
triggered = true;
|
||||
}
|
||||
|
||||
static void ptimer_test_expire_qemu_timers(int64_t expire_time,
|
||||
QEMUClockType type)
|
||||
{
|
||||
QEMUTimerList *timer_list = main_loop_tlg.tl[type];
|
||||
QEMUTimer *t = timer_list->active_timers.next;
|
||||
|
||||
while (t != NULL) {
|
||||
if (t->expire_time == expire_time) {
|
||||
timer_del(t);
|
||||
|
||||
if (t->cb != NULL) {
|
||||
t->cb(t->opaque);
|
||||
}
|
||||
}
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void ptimer_test_set_qemu_time_ns(int64_t ns)
|
||||
{
|
||||
ptimer_test_time_ns = ns;
|
||||
}
|
||||
|
||||
static void qemu_clock_step(uint64_t ns)
|
||||
{
|
||||
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||
int64_t advanced_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns;
|
||||
|
||||
while (deadline != -1 && deadline <= advanced_time) {
|
||||
ptimer_test_set_qemu_time_ns(deadline);
|
||||
ptimer_test_expire_qemu_timers(deadline, QEMU_CLOCK_VIRTUAL);
|
||||
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
|
||||
}
|
||||
|
||||
ptimer_test_set_qemu_time_ns(advanced_time);
|
||||
}
|
||||
|
||||
static void check_set_count(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_count(ptimer, 1000);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 1000);
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void check_set_limit(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_limit(ptimer, 1000, 0);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 1000);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_limit(ptimer, 2000, 1);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 2000);
|
||||
g_assert_cmpuint(ptimer_get_limit(ptimer), ==, 2000);
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void check_oneshot(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_set_count(ptimer, 10);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 * 2 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 11);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 * 7 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(4000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_count(ptimer, 10);
|
||||
|
||||
qemu_clock_step(20000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_limit(ptimer, 9, 1);
|
||||
|
||||
qemu_clock_step(20000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_count(ptimer, 20);
|
||||
|
||||
qemu_clock_step(2000000 * 19 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 * 12 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void check_periodic(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_set_limit(ptimer, 10, 1);
|
||||
ptimer_run(ptimer, 0);
|
||||
|
||||
qemu_clock_step(2000000 * 10 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_count(ptimer, 20);
|
||||
|
||||
qemu_clock_step(2000000 * 11 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 10);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
|
||||
g_assert_true(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_count(ptimer, 3);
|
||||
ptimer_run(ptimer, 0);
|
||||
|
||||
qemu_clock_step(2000000 * 3 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 8);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_count(ptimer, 0);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 10);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 * 12 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_true(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 * 12 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_run(ptimer, 0);
|
||||
ptimer_set_period(ptimer, 0);
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 7);
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void check_on_the_fly_mode_change(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_set_limit(ptimer, 10, 1);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 * 9 + 100000);
|
||||
|
||||
ptimer_run(ptimer, 0);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 9);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 * 9);
|
||||
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 3);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
}
|
||||
|
||||
static void check_on_the_fly_period_change(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_set_limit(ptimer, 8, 1);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 * 4 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_period(ptimer, 4000000);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
|
||||
|
||||
qemu_clock_step(4000000 * 2 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(4000000 * 2);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
}
|
||||
|
||||
static void check_on_the_fly_freq_change(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_freq(ptimer, 500);
|
||||
ptimer_set_limit(ptimer, 8, 1);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(2000000 * 4 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_set_freq(ptimer, 250);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 3);
|
||||
|
||||
qemu_clock_step(2000000 * 4 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 4);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
}
|
||||
|
||||
static void check_run_with_period_0(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_count(ptimer, 99);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
qemu_clock_step(10 * NANOSECONDS_PER_SECOND);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void check_run_with_delta_0(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_set_limit(ptimer, 99, 0);
|
||||
ptimer_run(ptimer, 1);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 97);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 2);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_count(ptimer, 0);
|
||||
ptimer_run(ptimer, 0);
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 99);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 97);
|
||||
g_assert_false(triggered);
|
||||
|
||||
qemu_clock_step(2000000 * 98);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 98);
|
||||
g_assert_true(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
}
|
||||
|
||||
static void check_periodic_with_load_0(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_run(ptimer, 0);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
ptimer_stop(ptimer);
|
||||
}
|
||||
|
||||
static void check_oneshot_with_load_0(gconstpointer arg)
|
||||
{
|
||||
const uint8_t *policy = arg;
|
||||
QEMUBH *bh = qemu_bh_new(ptimer_trigger, NULL);
|
||||
ptimer_state *ptimer = ptimer_init(bh, *policy);
|
||||
|
||||
triggered = false;
|
||||
|
||||
ptimer_set_period(ptimer, 2000000);
|
||||
ptimer_run(ptimer, 1);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_true(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_cmpuint(ptimer_get_count(ptimer), ==, 0);
|
||||
g_assert_false(triggered);
|
||||
|
||||
triggered = false;
|
||||
|
||||
qemu_clock_step(2000000 + 100000);
|
||||
|
||||
g_assert_false(triggered);
|
||||
}
|
||||
|
||||
static void add_ptimer_tests(uint8_t policy)
|
||||
{
|
||||
uint8_t *ppolicy = g_malloc(1);
|
||||
char *policy_name = g_malloc(64);
|
||||
|
||||
*ppolicy = policy;
|
||||
|
||||
if (policy == PTIMER_POLICY_DEFAULT) {
|
||||
g_sprintf(policy_name, "default");
|
||||
}
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/set_count policy=%s", policy_name),
|
||||
ppolicy, check_set_count);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/set_limit policy=%s", policy_name),
|
||||
ppolicy, check_set_limit);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/oneshot policy=%s", policy_name),
|
||||
ppolicy, check_oneshot);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/periodic policy=%s", policy_name),
|
||||
ppolicy, check_periodic);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/on_the_fly_mode_change policy=%s", policy_name),
|
||||
ppolicy, check_on_the_fly_mode_change);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/on_the_fly_period_change policy=%s", policy_name),
|
||||
ppolicy, check_on_the_fly_period_change);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/on_the_fly_freq_change policy=%s", policy_name),
|
||||
ppolicy, check_on_the_fly_freq_change);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/run_with_period_0 policy=%s", policy_name),
|
||||
ppolicy, check_run_with_period_0);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/run_with_delta_0 policy=%s", policy_name),
|
||||
ppolicy, check_run_with_delta_0);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/periodic_with_load_0 policy=%s", policy_name),
|
||||
ppolicy, check_periodic_with_load_0);
|
||||
|
||||
qtest_add_data_func(
|
||||
g_strdup_printf("/ptimer/oneshot_with_load_0 policy=%s", policy_name),
|
||||
ppolicy, check_oneshot_with_load_0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
for (i = 0; i < QEMU_CLOCK_MAX; i++) {
|
||||
main_loop_tlg.tl[i] = g_new0(QEMUTimerList, 1);
|
||||
}
|
||||
|
||||
add_ptimer_tests(PTIMER_POLICY_DEFAULT);
|
||||
|
||||
qtest_allowed = true;
|
||||
|
||||
return g_test_run();
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* QTest testcase for the ptimer
|
||||
*
|
||||
* Author: Dmitry Osipenko <digetx@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 PTIMER_TEST_H
|
||||
#define PTIMER_TEST_H
|
||||
|
||||
extern bool qtest_allowed;
|
||||
|
||||
extern int64_t ptimer_test_time_ns;
|
||||
|
||||
struct QEMUTimerList {
|
||||
QEMUTimer active_timers;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue