Re: [PATCH v8 04/10] hw/intc: GICv3 ITS Command processing
mapti(s, data, cq_offset, false); > break; > case GITS_CMD_MAPI: > +res = process_mapti(s, data, cq_offset, true); > break; > case GITS_CMD_DISCARD: > +res = process_its_cmd(s, data, cq_offset, DISCARD); > break; > case GITS_CMD_INV: > case GITS_CMD_INVALL: > @@ -486,7 +824,20 @@ static MemTxResult gicv3_its_translation_write(void > *opaque, hwaddr offset, > uint64_t data, unsigned size, > MemTxAttrs attrs) > { > +GICv3ITSState *s = (GICv3ITSState *)opaque; > MemTxResult result = MEMTX_OK; > +uint32_t devid = 0; > + > +switch (offset) { > +case GITS_TRANSLATER: > +if (s->ctlr & ITS_CTLR_ENABLED) { > +devid = attrs.requester_id; > +result = process_its_cmd(s, data, devid, NONE); > +} > +break; > +default: > +break; > +} > > return result; > } > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > index 034fadfebe..1966444790 100644 > --- a/hw/intc/gicv3_internal.h > +++ b/hw/intc/gicv3_internal.h > @@ -334,6 +334,13 @@ FIELD(MAPC, RDBASE, 16, 32) > #define ITTADDR_MASK MAKE_64BIT_MASK(ITTADDR_SHIFT, > ITTADDR_LENGTH) > #define SIZE_MASK 0x1f > > +/* MAPI command fields */ > +#define EVENTID_MASK ((1ULL << 32) - 1) > + > +/* MAPTI command fields */ > +#define pINTID_SHIFT 32 > +#define pINTID_MASK MAKE_64BIT_MASK(32, 32) > + > #define DEVID_SHIFT 32 > #define DEVID_MASKMAKE_64BIT_MASK(32, 32) > > @@ -359,6 +366,11 @@ FIELD(MAPC, RDBASE, 16, 32) > * Values: | vPEID| ICID | > */ > #define ITS_ITT_ENTRY_SIZE0xC > +#define ITE_ENTRY_INTTYPE_SHIFT1 > +#define ITE_ENTRY_INTID_SHIFT 2 > +#define ITE_ENTRY_INTID_MASK MAKE_64BIT_MASK(2, 24) > +#define ITE_ENTRY_INTSP_SHIFT 26 > +#define ITE_ENTRY_ICID_MASK MAKE_64BIT_MASK(0, 16) > > /* 16 bits EventId */ > #define ITS_IDBITS GICD_TYPER_IDBITS > diff --git a/include/hw/intc/arm_gicv3_common.h > b/include/hw/intc/arm_gicv3_common.h > index 1fd5cedbbd..0715b0bc2a 100644 > --- a/include/hw/intc/arm_gicv3_common.h > +++ b/include/hw/intc/arm_gicv3_common.h > @@ -36,6 +36,8 @@ > #define GICV3_MAXIRQ 1020 > #define GICV3_MAXSPI (GICV3_MAXIRQ - GIC_INTERNAL) > > +#define GICV3_LPI_INTID_START 8192 > + > #define GICV3_REDIST_SIZE 0x2 > > /* Number of SGI target-list bits */ > Thanks for fixing ! Tested-by: Neil Armstrong
[PATCH] misc: edu: add MSI-X interrupt generation aswell
Add MSI-X aswell since either MSI or MSI-X are optional and MSI can still be used without any issues. Signed-off-by: Neil Armstrong --- hw/misc/edu.c | 15 ++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index e935c418d4..5d0643e1bd 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -27,6 +27,7 @@ #include "hw/pci/pci.h" #include "hw/hw.h" #include "hw/pci/msi.h" +#include "hw/pci/msix.h" #include "qemu/timer.h" #include "qom/object.h" #include "qemu/main-loop.h" /* iothread mutex */ @@ -77,6 +78,11 @@ struct EduState { uint64_t dma_mask; }; +static bool edu_msix_enabled(EduState *edu) +{ +return msix_enabled(>pdev); +} + static bool edu_msi_enabled(EduState *edu) { return msi_enabled(>pdev); @@ -86,7 +92,9 @@ static void edu_raise_irq(EduState *edu, uint32_t val) { edu->irq_status |= val; if (edu->irq_status) { -if (edu_msi_enabled(edu)) { +if (edu_msix_enabled(edu)) { +msix_notify(>pdev, 0); +} else if (edu_msi_enabled(edu)) { msi_notify(>pdev, 0); } else { pci_set_irq(>pdev, 1); @@ -369,6 +377,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp) if (msi_init(pdev, 0, 1, true, false, errp)) { return; } +if (msix_init_exclusive_bar(pdev, 1, 1, errp)) { +return; +} +msix_vector_use(pdev, 0); timer_init_ms(>dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); @@ -397,6 +409,7 @@ static void pci_edu_uninit(PCIDevice *pdev) timer_del(>dma_timer); msi_uninit(pdev); +msix_uninit_exclusive_bar(pdev); } static void edu_instance_init(Object *obj) -- 2.25.1
Re: [PATCH v7 05/10] hw/intc: GICv3 ITS Feature enablement
MTX_OK; > case GICR_STATUSR: > /* RAZ/WI for our implementation */ > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > index 1966444790..530d1c1789 100644 > --- a/hw/intc/gicv3_internal.h > +++ b/hw/intc/gicv3_internal.h > @@ -68,6 +68,8 @@ > #define GICD_CTLR_E1NWF (1U << 7) > #define GICD_CTLR_RWP (1U << 31) > > +#define GICD_TYPER_LPIS_SHIFT 17 > + > /* 16 bits EventId */ > #define GICD_TYPER_IDBITS0xf > > diff --git a/include/hw/intc/arm_gicv3_common.h > b/include/hw/intc/arm_gicv3_common.h > index 0715b0bc2a..c1348cc60a 100644 > --- a/include/hw/intc/arm_gicv3_common.h > +++ b/include/hw/intc/arm_gicv3_common.h > @@ -221,6 +221,7 @@ struct GICv3State { > uint32_t num_cpu; > uint32_t num_irq; > uint32_t revision; > +bool lpi_enable; > bool security_extn; > bool irq_reset_nonsecure; > bool gicd_no_migration_shift_bug; > Tested with in-review Zephyr ITS implementation at https://github.com/zephyrproject-rtos/zephyr/pull/37506 Tested-by: Neil Armstrong
Re: [PATCH v7 02/10] hw/intc: GICv3 ITS register definitions added
st write to RO register at offset " > + TARGET_FMT_plx "\n", __func__, offset); > +break; > +default: > +result = MEMTX_ERROR; > +break; > +} > return result; > } > > @@ -66,7 +407,29 @@ static MemTxResult its_readll(GICv3ITSState *s, hwaddr > offset, >uint64_t *data, MemTxAttrs attrs) > { > MemTxResult result = MEMTX_OK; > +int index; > > +switch (offset) { > +case GITS_TYPER: > +*data = s->typer; > +break; > +case GITS_BASER ... GITS_BASER + 0x3f: > +index = (offset - GITS_BASER) / 8; > +*data = s->baser[index]; > +break; > +case GITS_CBASER: > +*data = s->cbaser; > +break; > +case GITS_CREADR: > +*data = s->creadr; > +break; > +case GITS_CWRITER: > +*data = s->cwriter; > +break; > +default: > +result = MEMTX_ERROR; > +break; > +} > return result; > } > > @@ -170,6 +533,9 @@ static void gicv3_arm_its_realize(DeviceState *dev, Error > **errp) > > gicv3_its_init_mmio(s, _its_control_ops, > _its_translation_ops); > > +address_space_init(>gicv3->dma_as, s->gicv3->dma, > + "gicv3-its-sysmem"); > + > /* set the ITS default features supported */ > s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, >GITS_TYPE_PHYSICAL); > @@ -213,6 +579,14 @@ static void gicv3_its_reset(DeviceState *dev) > GITS_CTE_SIZE - 1); > } > > +static void gicv3_its_post_load(GICv3ITSState *s) > +{ > +if (s->ctlr & ITS_CTLR_ENABLED) { > +extract_table_params(s); > +extract_cmdq_params(s); > +} > +} > + > static Property gicv3_its_props[] = { > DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3", > GICv3State *), > @@ -223,10 +597,12 @@ static void gicv3_its_class_init(ObjectClass *klass, > void *data) > { > DeviceClass *dc = DEVICE_CLASS(klass); > GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass); > +GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass); > > dc->realize = gicv3_arm_its_realize; > device_class_set_props(dc, gicv3_its_props); > device_class_set_parent_reset(dc, gicv3_its_reset, >parent_reset); > +icc->post_load = gicv3_its_post_load; > } > > static const TypeInfo gicv3_its_info = { > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > index b99bf9db46..92e0a4fa68 100644 > --- a/hw/intc/gicv3_internal.h > +++ b/hw/intc/gicv3_internal.h > @@ -258,6 +258,20 @@ FIELD(GITS_BASER, INNERCACHE, 59, 3) > FIELD(GITS_BASER, INDIRECT, 62, 1) > FIELD(GITS_BASER, VALID, 63, 1) > > +FIELD(GITS_CBASER, SIZE, 0, 8) > +FIELD(GITS_CBASER, SHAREABILITY, 10, 2) > +FIELD(GITS_CBASER, PHYADDR, 12, 40) > +FIELD(GITS_CBASER, OUTERCACHE, 53, 3) > +FIELD(GITS_CBASER, INNERCACHE, 59, 3) > +FIELD(GITS_CBASER, VALID, 63, 1) > + > +FIELD(GITS_CREADR, STALLED, 0, 1) > +FIELD(GITS_CREADR, OFFSET, 5, 15) > + > +FIELD(GITS_CWRITER, RETRY, 0, 1) > +FIELD(GITS_CWRITER, OFFSET, 5, 15) > + > +FIELD(GITS_CTLR, ENABLED, 0, 1) > FIELD(GITS_CTLR, QUIESCENT, 31, 1) > > FIELD(GITS_TYPER, PHYSICAL, 0, 1) > @@ -269,6 +283,13 @@ FIELD(GITS_TYPER, PTA, 19, 1) > FIELD(GITS_TYPER, CIDBITS, 32, 4) > FIELD(GITS_TYPER, CIL, 36, 1) > > +#define GITS_IDREGS 0xFFD0 > + > +#define ITS_CTLR_ENABLED (1U) /* ITS Enabled */ > + > +#define GITS_BASER_RO_MASK (R_GITS_BASER_ENTRYSIZE_MASK | \ > + R_GITS_BASER_TYPE_MASK) > + > #define GITS_BASER_PAGESIZE_4K0 > #define GITS_BASER_PAGESIZE_16K 1 > #define GITS_BASER_PAGESIZE_64K 2 > @@ -276,6 +297,14 @@ FIELD(GITS_TYPER, CIL, 36, 1) > #define GITS_BASER_TYPE_DEVICE 1ULL > #define GITS_BASER_TYPE_COLLECTION 4ULL > > +#define GITS_PAGE_SIZE_4K 0x1000 > +#define GITS_PAGE_SIZE_16K 0x4000 > +#define GITS_PAGE_SIZE_64K 0x1 > + > +#define L1TABLE_ENTRY_SIZE 8 > + > +#define GITS_CMDQ_ENTRY_SIZE 32 > + > /** > * Default features advertised by this version of ITS > */ > diff --git a/include/hw/intc/arm_gicv3_common.h > b/include/hw/intc/arm_gicv3_common.h > index 91491a2f66..1fd5cedbbd 100644 > --- a/include/hw/intc/arm_gicv3_common.h > +++ b/include/hw/intc/arm_gicv3_common.h > @@ -226,6 +226,9 @@ struct GICv3State { > int dev_fd; /* kvm device fd if backed by kvm vgic support */ > Error *migration_blocker; > > +MemoryRegion *dma; > +AddressSpace dma_as; > + > /* Distributor */ > > /* for a GIC with the security extensions the NS banked version of this > diff --git a/include/hw/intc/arm_gicv3_its_common.h > b/include/hw/intc/arm_gicv3_its_common.h > index 65d1191db1..4e79145dde 100644 > --- a/include/hw/intc/arm_gicv3_its_common.h > +++ b/include/hw/intc/arm_gicv3_its_common.h > @@ -41,6 +41,25 @@ > > #define GITS_TRANSLATER 0x0040 > > +typedef struct { > +bool valid; > +bool indirect; > +uint16_t entry_sz; > +uint32_t page_sz; > +uint32_t max_entries; > +union { > +uint32_t max_devids; > +uint32_t max_collids; > +} maxids; > +uint64_t base_addr; > +} TableDesc; > + > +typedef struct { > +bool valid; > +uint32_t max_entries; > +uint64_t base_addr; > +} CmdQDesc; > + > struct GICv3ITSState { > SysBusDevice parent_obj; > > @@ -63,6 +82,10 @@ struct GICv3ITSState { > uint64_t creadr; > uint64_t baser[8]; > > +TableDesc dt; > +TableDesc ct; > +CmdQDesc cq; > + > Error *migration_blocker; > }; > > Tested with in-review Zephyr ITS implementation at https://github.com/zephyrproject-rtos/zephyr/pull/37506 Tested-by: Neil Armstrong
Re: [PATCH v7 03/10] hw/intc: GICv3 ITS command queue framework
+break; > +case GITS_CMD_CLEAR: > +break; > +case GITS_CMD_SYNC: > +/* > + * Current implementation makes a blocking synchronous call > + * for every command issued earlier, hence the internal state > + * is already consistent by the time SYNC command is executed. > + * Hence no further processing is required for SYNC command. > + */ > +break; > +case GITS_CMD_MAPD: > +res = process_mapd(s, data, cq_offset); > +break; > +case GITS_CMD_MAPC: > +res = process_mapc(s, cq_offset); > +break; > +case GITS_CMD_MAPTI: > +break; > +case GITS_CMD_MAPI: > +break; > +case GITS_CMD_DISCARD: > +break; > +case GITS_CMD_INV: > +case GITS_CMD_INVALL: > +break; > +default: > +break; > +} > +if (res == MEMTX_OK) { > +rd_offset++; > +rd_offset %= s->cq.max_entries; > +s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, > rd_offset); > +} else { > +/* > + * in this implementation, in case of dma read/write error > + * we stall the command processing > + */ > +s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1); > +qemu_log_mask(LOG_GUEST_ERROR, > + "%s: %x cmd processing failed\n", __func__, cmd); > +break; > +} > +} > +} > + > /* > * This function extracts the ITS Device and Collection table specific > * parameters (like base_addr, size etc) from GITS_BASER register. > @@ -206,6 +505,7 @@ static MemTxResult its_writel(GICv3ITSState *s, hwaddr > offset, > extract_table_params(s); > extract_cmdq_params(s); > s->creadr = 0; > +process_cmdq(s); > } > break; > case GITS_CBASER: > @@ -233,6 +533,9 @@ static MemTxResult its_writel(GICv3ITSState *s, hwaddr > offset, > case GITS_CWRITER: > s->cwriter = deposit64(s->cwriter, 0, 32, > (value & ~R_GITS_CWRITER_RETRY_MASK)); > +if (s->cwriter != s->creadr) { > +process_cmdq(s); > +} > break; > case GITS_CWRITER + 4: > s->cwriter = deposit64(s->cwriter, 32, 32, value); > @@ -379,6 +682,9 @@ static MemTxResult its_writell(GICv3ITSState *s, hwaddr > offset, > break; > case GITS_CWRITER: > s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK; > +if (s->cwriter != s->creadr) { > +process_cmdq(s); > +} > break; > case GITS_CREADR: > if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) { > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > index 92e0a4fa68..034fadfebe 100644 > --- a/hw/intc/gicv3_internal.h > +++ b/hw/intc/gicv3_internal.h > @@ -304,6 +304,43 @@ FIELD(GITS_TYPER, CIL, 36, 1) > #define L1TABLE_ENTRY_SIZE 8 > > #define GITS_CMDQ_ENTRY_SIZE 32 > +#define NUM_BYTES_IN_DW 8 > + > +#define CMD_MASK 0xff > + > +/* ITS Commands */ > +#define GITS_CMD_CLEAR0x04 > +#define GITS_CMD_DISCARD 0x0F > +#define GITS_CMD_INT 0x03 > +#define GITS_CMD_MAPC 0x09 > +#define GITS_CMD_MAPD 0x08 > +#define GITS_CMD_MAPI 0x0B > +#define GITS_CMD_MAPTI0x0A > +#define GITS_CMD_INV 0x0C > +#define GITS_CMD_INVALL 0x0D > +#define GITS_CMD_SYNC 0x05 > + > +/* MAPC command fields */ > +#define ICID_LENGTH 16 > +#define ICID_MASK ((1U << ICID_LENGTH) - 1) > +FIELD(MAPC, RDBASE, 16, 32) > + > +#define RDBASE_PROCNUM_LENGTH16 > +#define RDBASE_PROCNUM_MASK ((1ULL << RDBASE_PROCNUM_LENGTH) - 1) > + > +/* MAPD command fields */ > +#define ITTADDR_LENGTH 44 > +#define ITTADDR_SHIFT 8 > +#define ITTADDR_MASK MAKE_64BIT_MASK(ITTADDR_SHIFT, > ITTADDR_LENGTH) > +#define SIZE_MASK 0x1f > + > +#define DEVID_SHIFT 32 > +#define DEVID_MASKMAKE_64BIT_MASK(32, 32) > + > +#define VALID_SHIFT 63 > +#define CMD_FIELD_VALID_MASK (1ULL << VALID_SHIFT) > +#define L2_TABLE_VALID_MASK CMD_FIELD_VALID_MASK > +#define TABLE_ENTRY_VALID_MASK(1ULL << 0) > > /** > * Default features advertised by this version of ITS > @@ -337,6 +374,9 @@ FIELD(GITS_TYPER, CIL, 36, 1) > * Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits > */ > #define GITS_DTE_SIZE (0x8ULL) > +#define GITS_DTE_ITTADDR_SHIFT 6 > +#define GITS_DTE_ITTADDR_MASK > MAKE_64BIT_MASK(GITS_DTE_ITTADDR_SHIFT, \ > + ITTADDR_LENGTH) > > /* > * 8 bytes Collection Table Entry size > Tested with in-review Zephyr ITS implementation at https://github.com/zephyrproject-rtos/zephyr/pull/37506 Tested-by: Neil Armstrong
Re: [PATCH v7 06/10] hw/intc: GICv3 redistributor ITS processing
> +cs->hpplpi.prio = 0xff; > + > +lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; > + > +/* Determine the highest priority pending interrupt among LPIs */ > +pendt_size = (1ULL << (idbits + 1)); > + > +for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) { > +address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, > , > + sizeof(pend)); > + > +while (pend) { > +bit = ctz32(pend); > +gicv3_redist_check_lpi_priority(cs, i * 8 + bit); > +pend &= ~(1 << bit); > +} > +} > +} > + > +void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level) > +{ > +/* > + * This function updates the pending bit in lpi pending table for > + * the irq being activated or deactivated. > + */ > +AddressSpace *as = >gic->dma_as; > +uint64_t lpipt_baddr; > +bool ispend = false; > +uint8_t pend; > + > +/* > + * get the bit value corresponding to this irq in the > + * lpi pending table > + */ > +lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK; > + > +address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), > + MEMTXATTRS_UNSPECIFIED, , sizeof(pend)); > + > +ispend = extract32(pend, irq % 8, 1); > + > +/* no change in the value of pending bit, return */ > +if (ispend == level) { > +return; > +} > +pend = deposit32(pend, irq % 8, 1, level ? 1 : 0); > + > +address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)), > +MEMTXATTRS_UNSPECIFIED, , sizeof(pend)); > + > +/* > + * check if this LPI is better than the current hpplpi, if yes > + * just set hpplpi.prio and .irq without doing a full rescan > + */ > +if (level) { > +gicv3_redist_check_lpi_priority(cs, irq); > +} else { > +if (irq == cs->hpplpi.irq) { > +gicv3_redist_update_lpi(cs); > +} > +} > +} > + > +void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level) > +{ > +uint64_t idbits; > + > +idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS), > + GICD_TYPER_IDBITS); > + > +if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser || > + !cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) || > + irq < GICV3_LPI_INTID_START) { > +return; > +} > + > +/* set/clear the pending bit for this irq */ > +gicv3_redist_lpi_pending(cs, irq, level); > + > +gicv3_redist_update(cs); > +} > + > void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level) > { > /* Update redistributor state for a change in an external PPI input line > */ > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > index 530d1c1789..a0369dace7 100644 > --- a/hw/intc/gicv3_internal.h > +++ b/hw/intc/gicv3_internal.h > @@ -140,6 +140,8 @@ FIELD(GICR_PENDBASER, PHYADDR, 16, 36) > FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3) > FIELD(GICR_PENDBASER, PTZ, 62, 1) > > +#define GICR_PROPBASER_IDBITS_THRESHOLD 0xd > + > #define ICC_CTLR_EL1_CBPR (1U << 0) > #define ICC_CTLR_EL1_EOIMODE(1U << 1) > #define ICC_CTLR_EL1_PMHE (1U << 6) > @@ -305,6 +307,9 @@ FIELD(GITS_TYPER, CIL, 36, 1) > > #define L1TABLE_ENTRY_SIZE 8 > > +#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK > +#define LPI_PRIORITY_MASK 0xfc > + > #define GITS_CMDQ_ENTRY_SIZE 32 > #define NUM_BYTES_IN_DW 8 > > @@ -397,6 +402,7 @@ FIELD(MAPC, RDBASE, 16, 32) > * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE) > */ > #define GITS_CTE_SIZE (0x8ULL) > +#define GITS_CTE_RDBASE_PROCNUM_MASK MAKE_64BIT_MASK(1, > RDBASE_PROCNUM_LENGTH) > > /* Special interrupt IDs */ > #define INTID_SECURE 1020 > @@ -455,6 +461,9 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr > offset, uint64_t data, > unsigned size, MemTxAttrs attrs); > void gicv3_dist_set_irq(GICv3State *s, int irq, int level); > void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level); > +void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level); > +void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level); > +void gicv3_redist_update_lpi(GICv3CPUState *cs); > void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns); > void gicv3_init_cpuif(GICv3State *s); > > diff --git a/include/hw/intc/arm_gicv3_common.h > b/include/hw/intc/arm_gicv3_common.h > index c1348cc60a..aa4f0d6770 100644 > --- a/include/hw/intc/arm_gicv3_common.h > +++ b/include/hw/intc/arm_gicv3_common.h > @@ -204,6 +204,13 @@ struct GICv3CPUState { > * real state above; it doesn't need to be migrated. > */ > PendingIrq hppi; > + > +/* > + * Cached information recalculated from LPI tables > + * in guest memory > + */ > +PendingIrq hpplpi; > + > /* This is temporary working state, to avoid a malloc in gicv3_update() > */ > bool seenbetter; > }; > Tested with in-review Zephyr ITS implementation at https://github.com/zephyrproject-rtos/zephyr/pull/37506 Tested-by: Neil Armstrong
Re: [PATCH v7 01/10] hw/intc: GICv3 ITS initial framework
ITS_BASER, SIZE, 0, 8) > +FIELD(GITS_BASER, PAGESIZE, 8, 2) > +FIELD(GITS_BASER, SHAREABILITY, 10, 2) > +FIELD(GITS_BASER, PHYADDR, 12, 36) > +FIELD(GITS_BASER, PHYADDRL_64K, 16, 32) > +FIELD(GITS_BASER, PHYADDRH_64K, 12, 4) > +FIELD(GITS_BASER, ENTRYSIZE, 48, 5) > +FIELD(GITS_BASER, OUTERCACHE, 53, 3) > +FIELD(GITS_BASER, TYPE, 56, 3) > +FIELD(GITS_BASER, INNERCACHE, 59, 3) > +FIELD(GITS_BASER, INDIRECT, 62, 1) > +FIELD(GITS_BASER, VALID, 63, 1) > + > +FIELD(GITS_CTLR, QUIESCENT, 31, 1) > + > +FIELD(GITS_TYPER, PHYSICAL, 0, 1) > +FIELD(GITS_TYPER, ITT_ENTRY_SIZE, 4, 4) > +FIELD(GITS_TYPER, IDBITS, 8, 5) > +FIELD(GITS_TYPER, DEVBITS, 13, 5) > +FIELD(GITS_TYPER, SEIS, 18, 1) > +FIELD(GITS_TYPER, PTA, 19, 1) > +FIELD(GITS_TYPER, CIDBITS, 32, 4) > +FIELD(GITS_TYPER, CIL, 36, 1) > + > +#define GITS_BASER_PAGESIZE_4K0 > +#define GITS_BASER_PAGESIZE_16K 1 > +#define GITS_BASER_PAGESIZE_64K 2 > + > +#define GITS_BASER_TYPE_DEVICE 1ULL > +#define GITS_BASER_TYPE_COLLECTION 4ULL > + > +/** > + * Default features advertised by this version of ITS > + */ > +/* Physical LPIs supported */ > +#define GITS_TYPE_PHYSICAL (1U << 0) > + > +/* > + * 12 bytes Interrupt translation Table Entry size > + * as per Table 5.3 in GICv3 spec > + * ITE Lower 8 Bytes > + * Bits:| 49 ... 26 | 25 ... 2 | 1 | 0| > + * Values: |1023 | IntNum | IntType | Valid | > + * ITE Higher 4 Bytes > + * Bits:| 31 ... 16 | 15 ...0 | > + * Values: | vPEID| ICID | > + */ > +#define ITS_ITT_ENTRY_SIZE0xC > + > +/* 16 bits EventId */ > +#define ITS_IDBITS GICD_TYPER_IDBITS > + > +/* 16 bits DeviceId */ > +#define ITS_DEVBITS 0xF > + > +/* 16 bits CollectionId */ > +#define ITS_CIDBITS 0xF > + > +/* > + * 8 bytes Device Table Entry size > + * Valid = 1 bit,ITTAddr = 44 bits,Size = 5 bits > + */ > +#define GITS_DTE_SIZE (0x8ULL) > + > +/* > + * 8 bytes Collection Table Entry size > + * Valid = 1 bit,RDBase = 36 bits(considering max RDBASE) > + */ > +#define GITS_CTE_SIZE (0x8ULL) > + > /* Special interrupt IDs */ > #define INTID_SECURE 1020 > #define INTID_NONSECURE 1021 > diff --git a/hw/intc/meson.build b/hw/intc/meson.build > index 6e52a166e3..4dcfea6aa8 100644 > --- a/hw/intc/meson.build > +++ b/hw/intc/meson.build > @@ -8,6 +8,7 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files( >'arm_gicv3_dist.c', >'arm_gicv3_its_common.c', >'arm_gicv3_redist.c', > + 'arm_gicv3_its.c', > )) > softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c')) > softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c')) > diff --git a/include/hw/intc/arm_gicv3_its_common.h > b/include/hw/intc/arm_gicv3_its_common.h > index 5a0952b404..65d1191db1 100644 > --- a/include/hw/intc/arm_gicv3_its_common.h > +++ b/include/hw/intc/arm_gicv3_its_common.h > @@ -25,17 +25,22 @@ > #include "hw/intc/arm_gicv3_common.h" > #include "qom/object.h" > > +#define TYPE_ARM_GICV3_ITS "arm-gicv3-its" > + > #define ITS_CONTROL_SIZE 0x1 > #define ITS_TRANS_SIZE 0x1 > #define ITS_SIZE (ITS_CONTROL_SIZE + ITS_TRANS_SIZE) > > #define GITS_CTLR0x0 > #define GITS_IIDR0x4 > +#define GITS_TYPER 0x8 > #define GITS_CBASER 0x80 > #define GITS_CWRITER 0x88 > #define GITS_CREADR 0x90 > #define GITS_BASER 0x100 > > +#define GITS_TRANSLATER 0x0040 > + > struct GICv3ITSState { > SysBusDevice parent_obj; > > @@ -52,6 +57,7 @@ struct GICv3ITSState { > /* Registers */ > uint32_t ctlr; > uint32_t iidr; > +uint64_t typer; > uint64_t cbaser; > uint64_t cwriter; > uint64_t creadr; > @@ -62,7 +68,8 @@ struct GICv3ITSState { > > typedef struct GICv3ITSState GICv3ITSState; > > -void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops); > +void gicv3_its_init_mmio(GICv3ITSState *s, const MemoryRegionOps *ops, > + const MemoryRegionOps *tops); > > #define TYPE_ARM_GICV3_ITS_COMMON "arm-gicv3-its-common" > typedef struct GICv3ITSCommonClass GICv3ITSCommonClass; > Tested with in-review Zephyr ITS implementation at https://github.com/zephyrproject-rtos/zephyr/pull/37506 Tested-by: Neil Armstrong
Re: [PATCH v7 04/10] hw/intc: GICv3 ITS Command processing
Hi, On 06/08/2021 00:29, Shashi Mallela wrote: > Added ITS command queue handling for MAPTI,MAPI commands,handled ITS > translation which triggers an LPI via INT command as well as write > to GITS_TRANSLATER register,defined enum to differentiate between ITS > command interrupt trigger and GITS_TRANSLATER based interrupt trigger. > Each of these commands make use of other functionalities implemented to > get device table entry,collection table entry or interrupt translation > table entry required for their processing. > > Signed-off-by: Shashi Mallela > Reviewed-by: Peter Maydell > --- > hw/intc/arm_gicv3_its.c| 348 + > hw/intc/gicv3_internal.h | 12 + > include/hw/intc/arm_gicv3_common.h | 2 + > 3 files changed, 362 insertions(+) > > diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c > index 8bdbebbeca..35308f1c32 100644 > --- a/hw/intc/arm_gicv3_its.c > +++ b/hw/intc/arm_gicv3_its.c > @@ -29,6 +29,22 @@ struct GICv3ITSClass { > void (*parent_reset)(DeviceState *dev); > }; > > +/* > + * This is an internal enum used to distinguish between LPI triggered > + * via command queue and LPI triggered via gits_translater write. > + */ > +typedef enum ItsCmdType { > +NONE = 0, /* internal indication for GITS_TRANSLATER write */ > +CLEAR = 1, > +DISCARD = 2, > +INT = 3, > +} ItsCmdType; > + > +typedef struct { > +uint32_t iteh; > +uint64_t itel; > +} IteEntry; > + > static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz) > { > uint64_t result = 0; > @@ -50,6 +66,320 @@ static uint64_t baser_base_addr(uint64_t value, uint32_t > page_sz) > return result; > } > > +static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte, > +MemTxResult *res) > +{ > +AddressSpace *as = >gicv3->dma_as; > +uint64_t l2t_addr; > +uint64_t value; > +bool valid_l2t; > +uint32_t l2t_id; > +uint32_t max_l2_entries; > + > +if (s->ct.indirect) { > +l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE); > + > +value = address_space_ldq_le(as, > + s->ct.base_addr + > + (l2t_id * L1TABLE_ENTRY_SIZE), > + MEMTXATTRS_UNSPECIFIED, res); > + > +if (*res == MEMTX_OK) { > +valid_l2t = (value & L2_TABLE_VALID_MASK) != 0; > + > +if (valid_l2t) { > +max_l2_entries = s->ct.page_sz / s->ct.entry_sz; > + > +l2t_addr = value & ((1ULL << 51) - 1); > + > +*cte = address_space_ldq_le(as, l2t_addr + > +((icid % max_l2_entries) * > GITS_CTE_SIZE), > +MEMTXATTRS_UNSPECIFIED, res); > + } > + } > +} else { > +/* Flat level table */ > +*cte = address_space_ldq_le(as, s->ct.base_addr + > + (icid * GITS_CTE_SIZE), > + MEMTXATTRS_UNSPECIFIED, res); > +} > + > +return (*cte & TABLE_ENTRY_VALID_MASK) != 0; > +} > + > +static MemTxResult update_ite(GICv3ITSState *s, uint32_t eventid, uint64_t > dte, > + IteEntry ite) > +{ > +AddressSpace *as = >gicv3->dma_as; > +uint64_t itt_addr; > +MemTxResult res = MEMTX_OK; > + > +itt_addr = (dte & GITS_DTE_ITTADDR_MASK) >> GITS_DTE_ITTADDR_SHIFT; > +itt_addr <<= ITTADDR_SHIFT; /* 256 byte aligned */ > + > +address_space_stq_le(as, itt_addr + (eventid * sizeof(uint64_t)), > + ite.itel, MEMTXATTRS_UNSPECIFIED, ); > + > +if (res == MEMTX_OK) { > +address_space_stl_le(as, itt_addr + ((eventid + sizeof(uint64_t)) * > + sizeof(uint32_t)), ite.iteh, > + MEMTXATTRS_UNSPECIFIED, ); While adding support for ITS on Zephyr, I've spotted an issue with the ITE entry storage here. >From eventid 0 to 7, it goes well, but from 8 and all even eventids, the table >gets trashed. The actual storage is: itel: itt_addr + (eventid * 8) iteh: itt_addr + ((eventid + 8) * 4) For the first eventIDs, the offsets are: EvenID iteliteh 0 0 32 1 8 36 2 16 40 3 24 44 4 32 48 5 40 52 6 48 56 7 56 60 8 64 64 <= the entry 8 simply disappears 9 72 68 10 80 72 <= trashed 9 11 88 76 12 96 80 <= trashes 10 and so on. The correct storage would be: address_space_stq_le(as, itt_addr + (eventid * (sizeof(uint64_t) + sizeof(uint32_t))), itel, MEMTXATTRS_UNSPECIFIED, ); if (res == MEMTX_OK) { address_space_stl_le(as, itt_addr + (eventid * (sizeof(uint64_t) + sizeof(uint32_t))) + sizeof(uint32_t), iteh, MEMTXATTRS_UNSPECIFIED,