Re: [PATCH v8 04/10] hw/intc: GICv3 ITS Command processing

2021-08-13 Thread Neil Armstrong
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

2021-08-12 Thread Neil Armstrong
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

2021-08-10 Thread Neil Armstrong
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

2021-08-10 Thread Neil Armstrong
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

2021-08-10 Thread Neil Armstrong
 +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

2021-08-10 Thread Neil Armstrong
> +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

2021-08-10 Thread Neil Armstrong
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

2021-08-06 Thread Neil Armstrong
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,