[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH v2 03/26] ARM: GICv3 ITS: allocate device and collection table
On Thu, 22 Dec 2016, Andre Przywara wrote: > Each ITS maps a pair of a DeviceID (usually the 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 the ITS. > The maximum number of devices is limited to a compile-time constant > exposed in Kconfig. > > Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx> > --- > xen/arch/arm/Kconfig | 6 +++ > xen/arch/arm/gic-its.c | 114 > ++++++++++++++++++++++++++++++++++++++++++ > xen/arch/arm/gic-v3.c | 5 ++ > xen/include/asm-arm/bitops.h | 1 + > xen/include/asm-arm/gic-its.h | 51 ++++++++++++++++++- > 5 files changed, 176 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig > index a7d941c..a369305 100644 > --- a/xen/arch/arm/Kconfig > +++ b/xen/arch/arm/Kconfig > @@ -59,6 +59,12 @@ config MAX_HOST_LPI_BITS > This can be overriden on the command line with the max_lpi_bits > parameter. > > +config MAX_ITS_PCI_BUSSES > + depends on HAS_ITS > + int "Number of PCI busses the ITS supports (4)" > + range 1 1024 > + default "4" Given that any kind of devices can be behind an ITS, including non-PCI devices, I think it is best to call this MAX_PHYS_ITS_DEVICES. > endmenu > > menu "ARM errata workaround via the alternative framework" > diff --git a/xen/arch/arm/gic-its.c b/xen/arch/arm/gic-its.c > index 6c3a35d..f1540b2 100644 > --- a/xen/arch/arm/gic-its.c > +++ b/xen/arch/arm/gic-its.c > @@ -22,6 +22,7 @@ > #include <xen/libfdt/libfdt.h> > #include <xen/sizes.h> > #include <asm/p2m.h> > +#include <asm/io.h> > #include <asm/gic.h> > #include <asm/gic_v3_defs.h> > #include <asm/gic-its.h> > @@ -37,6 +38,119 @@ static DEFINE_PER_CPU(void *, pending_table); > > #define MAX_PHYS_LPIS (BIT_ULL(lpi_data.host_lpi_bits) - 8192) > > +#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(58, 56) | GENMASK(52, 48)) > + > +static uint64_t encode_phys_addr(paddr_t addr, int page_bits) > +{ > + uint64_t ret; > + > + if ( page_bits < 16) > + return (uint64_t)addr & GENMASK(47, page_bits); > + > + ret = addr & GENMASK(47, 16); > + return ret | (addr & GENMASK(51, 48)) >> (48 - 12); > +} > + > +static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items) > +{ > + uint64_t attr; > + int entry_size = ((regc >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1; > + int pagesz; > + int order; > + void *buffer = NULL; > + > + 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; > + > + /* > + * Loop over the page sizes (4K, 16K, 64K) to find out what the host > + * supports. > + */ > + for ( pagesz = 0; pagesz < 3; pagesz++ ) > + { > + uint64_t reg; > + int nr_bytes; > + > + nr_bytes = ROUNDUP(nr_items * entry_size, BIT(pagesz * 2 + 12)); 12/PAGE_SHIFT > + order = get_order_from_bytes(nr_bytes); > + > + if ( !buffer ) > + buffer = alloc_xenheap_pages(order, 0); > + if ( !buffer ) > + return -ENOMEM; > + > + reg = attr; > + reg |= (pagesz << GITS_BASER_PAGE_SIZE_SHIFT); > + reg |= nr_bytes >> (pagesz * 2 + 12); > + reg |= regc & BASER_RO_MASK; > + reg |= GITS_BASER_VALID; > + reg |= encode_phys_addr(virt_to_maddr(buffer), pagesz * 2 + 12); > + > + writeq_relaxed(reg, basereg); > + regc = readl_relaxed(basereg); > + > + /* The host didn't like our attributes, just use what it returned. */ > + if ( (regc & BASER_ATTR_MASK) != attr ) > + attr = regc & BASER_ATTR_MASK; > + > + /* If the host accepted our page size, we are done. */ > + if ( (reg & (3UL << GITS_BASER_PAGE_SIZE_SHIFT)) == pagesz ) > + return 0; > + > + /* Check whether our buffer is aligned to the next page size > already. */ > + if ( !(virt_to_maddr(buffer) & (BIT(pagesz * 2 + 12 + 2) - 1)) ) > + { > + free_xenheap_pages(buffer, order); > + buffer = NULL; > + } Regardless of alignment, should we always free buffer here, given that we need to allocate the right size for the next attempt? > + } > + > + if ( buffer ) > + free_xenheap_pages(buffer, order); > + > + return -EINVAL; > +} > + > +int gicv3_its_init(struct host_its *hw_its) > +{ > + uint64_t reg; > + int i; > + > + hw_its->its_base = ioremap_nocache(hw_its->addr, hw_its->size); > + if ( !hw_its->its_base ) > + return -ENOMEM; > + > + for ( i = 0; i < GITS_BASER_NR_REGS; i++ ) > + { > + void __iomem *basereg = hw_its->its_base + GITS_BASER0 + i * 8; > + 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: > + /* TODO: find some better way of limiting the number of devices > */ > + its_map_baser(basereg, reg, CONFIG_MAX_ITS_PCI_BUSSES * 256); > + break; > + case GITS_BASER_TYPE_COLLECTION: > + its_map_baser(basereg, reg, NR_CPUS); > + break; > + default: > + continue; > + } > + } > + > + return 0; > +} > + > uint64_t gicv3_lpi_allocate_pendtable(void) > { > uint64_t reg, attr; > diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c > index 1c6869d..8ca7da2 100644 > --- a/xen/arch/arm/gic-v3.c > +++ b/xen/arch/arm/gic-v3.c > @@ -29,6 +29,7 @@ > #include <xen/irq.h> > #include <xen/iocap.h> > #include <xen/sched.h> > +#include <xen/err.h> > #include <xen/errno.h> > #include <xen/delay.h> > #include <xen/device_tree.h> > @@ -1564,6 +1565,7 @@ static int __init gicv3_init(void) > { > int res, i; > uint32_t reg; > + struct host_its *hw_its; > > if ( !cpu_has_gicv3 ) > { > @@ -1619,6 +1621,9 @@ static int __init gicv3_init(void) > res = gicv3_cpu_init(); > gicv3_hyp_init(); > > + list_for_each_entry(hw_its, &host_its_list, entry) > + gicv3_its_init(hw_its); > + > spin_unlock(&gicv3.lock); > > return res; > diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h > index c9adf79..4ccb444 100644 > --- a/xen/include/asm-arm/bitops.h > +++ b/xen/include/asm-arm/bitops.h > @@ -24,6 +24,7 @@ > #define BIT(nr) (1UL << (nr)) > #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_WORD)) > #define BIT_WORD(nr) ((nr) / BITS_PER_WORD) > +#define BIT_ULL(nr) (1ULL << (nr)) > #define BITS_PER_BYTE 8 > #define BIT_ULL(nr) (1ULL << (nr)) > > diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h > index a66b6be..26b0584 100644 > --- a/xen/include/asm-arm/gic-its.h > +++ b/xen/include/asm-arm/gic-its.h > @@ -18,6 +18,49 @@ > #ifndef __ASM_ARM_ITS_H__ > #define __ASM_ARM_ITS_H__ > > +#define LPI_OFFSET 8192 > + > +#define GITS_CTLR 0x000 > +#define GITS_IIDR 0x004 > +#define GITS_TYPER 0x008 > +#define GITS_CBASER 0x080 > +#define GITS_CWRITER 0x088 > +#define GITS_CREADR 0x090 > +#define GITS_BASER_NR_REGS 8 > +#define GITS_BASER0 0x100 > +#define GITS_BASER1 0x108 > +#define GITS_BASER2 0x110 > +#define GITS_BASER3 0x118 > +#define GITS_BASER4 0x120 > +#define GITS_BASER5 0x128 > +#define GITS_BASER6 0x130 > +#define GITS_BASER7 0x138 > + > +/* Register bits */ > +#define GITS_CTLR_ENABLE BIT_ULL(0) > +#define GITS_IIDR_VALUE 0x34c > + > +#define GITS_BASER_VALID BIT_ULL(63) > +#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_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) > + > #ifndef __ASSEMBLY__ > #include <xen/device_tree.h> > > @@ -27,6 +70,7 @@ struct host_its { > const struct dt_device_node *dt_node; > paddr_t addr; > paddr_t size; > + void __iomem *its_base; > }; > > extern struct list_head host_its_list; > @@ -42,8 +86,9 @@ void gicv3_its_dt_init(const struct dt_device_node *node); > uint64_t gicv3_lpi_get_proptable(void); > uint64_t gicv3_lpi_allocate_pendtable(void); > > -/* Initialize the host structures for LPIs. */ > +/* Initialize the host structures for LPIs and the host ITSes. */ > int gicv3_lpi_init_host_lpis(unsigned int nr_lpis); > +int gicv3_its_init(struct host_its *hw_its); > > #else > > @@ -62,6 +107,10 @@ static inline int gicv3_lpi_init_host_lpis(unsigned int > nr_lpis) > { > return 0; > } > +static inline int gicv3_its_init(struct host_its *hw_its) > +{ > + return 0; > +} > #endif /* CONFIG_HAS_ITS */ > > #endif /* __ASSEMBLY__ */ > -- > 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 |