|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 04/27] ARM: GICv3 ITS: allocate device and collection table
On Mon, 3 Apr 2017, Andre Przywara wrote:
> Each ITS maps a pair of a DeviceID (for instance derived from a PCI
> b/d/f triplet) and an EventID (the MSI payload or interrupt ID) to a
> pair of LPI number and collection ID, which points to the target CPU.
> This mapping is stored in the device and collection tables, which software
> has to provide for the ITS to use.
> Allocate the required memory and hand it to the ITS.
> The maximum number of devices can be limited to a compile-time variable.
>
> Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> ---
> xen/arch/arm/gic-v3-its.c | 132
> +++++++++++++++++++++++++++++++++++++++
> xen/include/asm-arm/gic_v3_its.h | 32 ++++++++++
> 2 files changed, 164 insertions(+)
>
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index 58c6ac0..00a1f7b 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -35,6 +35,105 @@ bool gicv3_its_host_has_its(void)
> return !list_empty(&host_its_list);
> }
>
> +#define BASER_ATTR_MASK \
> + ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT) | \
> + (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT) | \
> + (0x7UL << GITS_BASER_INNER_CACHEABILITY_SHIFT))
> +#define BASER_RO_MASK (GENMASK_ULL(58, 56) | GENMASK_ULL(52, 48))
> +
> +/* Check that the physical address can be encoded in the PROPBASER register.
> */
> +static bool check_baser_phys_addr(void *vaddr, unsigned int page_bits)
> +{
> + paddr_t paddr = virt_to_maddr(vaddr);
> +
> + return (!(paddr & ~GENMASK_ULL(page_bits < 16 ? 47 : 51, page_bits)));
> +}
> +
> +static uint64_t encode_baser_phys_addr(paddr_t addr, unsigned int page_bits)
> +{
> + uint64_t ret = addr & GENMASK_ULL(47, page_bits);
> +
> + if ( page_bits < 16 )
> + return ret;
> +
> + /* For 64K pages address bits 51-48 are encoded in bits 15-12. */
> + return ret | ((addr & GENMASK_ULL(51, 48)) >> (48 - 12));
> +}
> +
> +/* The ITS BASE registers work with page sizes of 4K, 16K or 64K. */
> +#define BASER_PAGE_BITS(sz) ((sz) * 2 + 12)
> +
> +static int its_map_baser(void __iomem *basereg, uint64_t regc,
> + unsigned int nr_items)
> +{
> + uint64_t attr, reg;
> + unsigned int entry_size = GITS_BASER_ENTRY_SIZE(regc);
> + unsigned int pagesz = 2; /* try 64K pages first, then go down. */
> + unsigned int table_size;
> + void *buffer;
> +
> + attr = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
> + attr |= GIC_BASER_CACHE_SameAsInner <<
> GITS_BASER_OUTER_CACHEABILITY_SHIFT;
> + attr |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
> +
> + /*
> + * Setup the BASE register with the attributes that we like. Then read
> + * it back and see what sticks (page size, cacheability and shareability
> + * attributes), retrying if necessary.
> + */
> +retry:
> + table_size = ROUNDUP(nr_items * entry_size,
> BIT(BASER_PAGE_BITS(pagesz)));
> + /* The BASE registers support at most 256 pages. */
> + table_size = min(table_size, 256U << BASER_PAGE_BITS(pagesz));
> +
> + buffer = _xzalloc(table_size, BIT(BASER_PAGE_BITS(pagesz)));
> + if ( !buffer )
> + return -ENOMEM;
> +
> + if ( !check_baser_phys_addr(buffer, BASER_PAGE_BITS(pagesz)) )
> + {
> + xfree(buffer);
> + return -ERANGE;
> + }
> +
> + reg = attr;
> + reg |= (pagesz << GITS_BASER_PAGE_SIZE_SHIFT);
> + reg |= (table_size >> BASER_PAGE_BITS(pagesz)) - 1;
> + reg |= regc & BASER_RO_MASK;
> + reg |= GITS_VALID_BIT;
> + reg |= encode_baser_phys_addr(virt_to_maddr(buffer),
> + BASER_PAGE_BITS(pagesz));
> +
> + writeq_relaxed(reg, basereg);
> + regc = readq_relaxed(basereg);
> +
> + /* The host didn't like our attributes, just use what it returned. */
> + if ( (regc & BASER_ATTR_MASK) != attr )
> + {
> + /* If we can't map it shareable, drop cacheability as well. */
> + if ( (regc & GITS_BASER_SHAREABILITY_MASK) == GIC_BASER_NonShareable
> )
> + {
> + regc &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
> + writeq_relaxed(regc, basereg);
> + }
> + attr = regc & BASER_ATTR_MASK;
> + }
> + if ( (regc & GITS_BASER_INNER_CACHEABILITY_MASK) <= GIC_BASER_CACHE_nC )
> + clean_and_invalidate_dcache_va_range(buffer, table_size);
> +
> + /* If the host accepted our page size, we are done. */
> + if ( ((regc >> GITS_BASER_PAGE_SIZE_SHIFT) & 0x3UL) == pagesz )
> + return 0;
> +
> + xfree(buffer);
> +
> + if ( pagesz-- > 0 )
> + goto retry;
> +
> + /* None of the page sizes was accepted, give up */
> + return -EINVAL;
> +}
> +
> /* Allow a user to limit the number of devices. */
> static unsigned int max_its_device_bits = 32;
> integer_param("max_its_device_bits", max_its_device_bits);
> @@ -42,6 +141,7 @@ integer_param("max_its_device_bits", max_its_device_bits);
> static int gicv3_its_init_single_its(struct host_its *hw_its)
> {
> uint64_t reg;
> + int i, ret;
>
> hw_its->its_base = ioremap_nocache(hw_its->addr, hw_its->size);
> if ( !hw_its->its_base )
> @@ -53,6 +153,38 @@ static int gicv3_its_init_single_its(struct host_its
> *hw_its)
> hw_its->evid_bits = GITS_TYPER_EVENT_ID_BITS(reg);
> hw_its->itte_size = GITS_TYPER_ITT_SIZE(reg);
>
> + for ( i = 0; i < GITS_BASER_NR_REGS; i++ )
> + {
> + void __iomem *basereg = hw_its->its_base + GITS_BASER0 + i * 8;
> + unsigned int type;
> +
> + reg = readq_relaxed(basereg);
> + type = (reg & GITS_BASER_TYPE_MASK) >> GITS_BASER_TYPE_SHIFT;
> + switch ( type )
> + {
> + case GITS_BASER_TYPE_NONE:
> + continue;
> + case GITS_BASER_TYPE_DEVICE:
> + ret = its_map_baser(basereg, reg, BIT(hw_its->devid_bits));
> + if ( ret )
> + return ret;
> + break;
> + case GITS_BASER_TYPE_COLLECTION:
> + ret = its_map_baser(basereg, reg, num_possible_cpus());
> + if ( ret )
> + return ret;
> + break;
> + /* In case this is a GICv4, provide a (dummy) vPE table as well. */
> + case GITS_BASER_TYPE_VCPU:
> + ret = its_map_baser(basereg, reg, 1);
> + if ( ret )
> + return ret;
> + break;
> + default:
> + continue;
> + }
> + }
> +
> return 0;
> }
>
> diff --git a/xen/include/asm-arm/gic_v3_its.h
> b/xen/include/asm-arm/gic_v3_its.h
> index 7c5a2fa..c7d8766 100644
> --- a/xen/include/asm-arm/gic_v3_its.h
> +++ b/xen/include/asm-arm/gic_v3_its.h
> @@ -37,6 +37,11 @@
> #define GITS_BASER7 0x138
>
> /* Register bits */
> +#define GITS_VALID_BIT BIT_ULL(63)
> +
> +#define GITS_CTLR_QUIESCENT BIT(31)
> +#define GITS_CTLR_ENABLE BIT(0)
> +
> #define GITS_TYPER_DEVIDS_SHIFT 13
> #define GITS_TYPER_DEVIDS_MASK (0x1fUL << GITS_TYPER_DEVIDS_SHIFT)
> #define GITS_TYPER_DEVICE_ID_BITS(r) (((r & GITS_TYPER_DEVIDS_MASK) >> \
> @@ -52,6 +57,33 @@
> #define GITS_TYPER_ITT_SIZE(r) ((((r) & GITS_TYPER_ITT_SIZE_MASK)
> >> \
> GITS_TYPER_ITT_SIZE_SHIFT)
> + 1)
>
> +#define GITS_IIDR_VALUE 0x34c
> +
> +#define GITS_BASER_INDIRECT BIT_ULL(62)
> +#define GITS_BASER_INNER_CACHEABILITY_SHIFT 59
> +#define GITS_BASER_TYPE_SHIFT 56
> +#define GITS_BASER_TYPE_MASK (7ULL << GITS_BASER_TYPE_SHIFT)
> +#define GITS_BASER_OUTER_CACHEABILITY_SHIFT 53
> +#define GITS_BASER_TYPE_NONE 0UL
> +#define GITS_BASER_TYPE_DEVICE 1UL
> +#define GITS_BASER_TYPE_VCPU 2UL
> +#define GITS_BASER_TYPE_CPU 3UL
> +#define GITS_BASER_TYPE_COLLECTION 4UL
> +#define GITS_BASER_TYPE_RESERVED5 5UL
> +#define GITS_BASER_TYPE_RESERVED6 6UL
> +#define GITS_BASER_TYPE_RESERVED7 7UL
> +#define GITS_BASER_ENTRY_SIZE_SHIFT 48
> +#define GITS_BASER_ENTRY_SIZE(reg) \
> + (((reg >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
> +#define GITS_BASER_SHAREABILITY_SHIFT 10
> +#define GITS_BASER_PAGE_SIZE_SHIFT 8
> +#define GITS_BASER_RO_MASK (GITS_BASER_TYPE_MASK | \
> + (31UL <<
> GITS_BASER_ENTRY_SIZE_SHIFT) |\
> + GITS_BASER_INDIRECT)
> +#define GITS_BASER_SHAREABILITY_MASK (0x3ULL <<
> GITS_BASER_SHAREABILITY_SHIFT)
> +#define GITS_BASER_OUTER_CACHEABILITY_MASK (0x7ULL <<
> GITS_BASER_OUTER_CACHEABILITY_SHIFT)
> +#define GITS_BASER_INNER_CACHEABILITY_MASK (0x7ULL <<
> GITS_BASER_INNER_CACHEABILITY_SHIFT)
> +
> #include <xen/device_tree.h>
>
> /* data structure for each hardware ITS */
> --
> 2.9.0
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |