|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 03/24] ARM: GICv3 ITS: allocate device and collection table
On Thu, 10 Nov 2016, Andre Przywara wrote:
> Hi,
>
> On 26/10/16 23:57, Stefano Stabellini wrote:
> > On Wed, 28 Sep 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.
> >> We limit the number of devices to cover 4 PCI busses for now.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
> >> ---
> >> xen/arch/arm/gic-its.c | 114
> >> ++++++++++++++++++++++++++++++++++++++++++
> >> xen/arch/arm/gic-v3.c | 5 ++
> >> xen/include/asm-arm/gic-its.h | 49 +++++++++++++++++-
> >> 3 files changed, 167 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/xen/arch/arm/gic-its.c b/xen/arch/arm/gic-its.c
> >> index b52dff3..40238a2 100644
> >> --- a/xen/arch/arm/gic-its.c
> >> +++ b/xen/arch/arm/gic-its.c
> >> @@ -21,6 +21,7 @@
> >> #include <xen/device_tree.h>
> >> #include <xen/libfdt/libfdt.h>
> >> #include <asm/p2m.h>
> >> +#include <asm/io.h>
> >> #include <asm/gic.h>
> >> #include <asm/gic_v3_defs.h>
> >> #include <asm/gic-its.h>
> >> @@ -38,6 +39,119 @@ static DEFINE_PER_CPU(void *, pending_table);
> >> min_t(unsigned int, lpi_data.host_lpi_bits, CONFIG_HOST_LPI_BITS)
> >> #define MAX_HOST_LPIS (BIT(MAX_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(52, 48) | GENMASK(58, 56))
> >> +
> >> +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 gicv3_map_baser(void __iomem *basereg, uint64_t regc, int
> >> nr_items)
> >
> > Shouldn't this be called its_map_baser?
>
> Yes, the BASER registers are an ITS property.
>
> >> +{
> >> + uint64_t attr;
> >> + int entry_size = (regc >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f;
> >
> > The spec says "This field is read-only and specifies the number of
> > bytes per entry, minus one." Do we need to increment it by 1?
>
> Mmh, looks so. I guess it worked because the number gets dwarfed by the
> page size round up below.
>
> >> + 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.
> >> + */
> >
> > Is this really the best way to do it? Can't we assume ITS supports 4K,
> > given that Xen requires 4K pages at the moment?
>
> The ITS pages are totally independent from the core's MMU page size.
> So the spec says: "If the GIC implementation supports only a single,
> fixed page size, this field might be RO."
> I take it that this means that the only implemented page size could be
> 64K, for instance. And in fact the KVM ITS emulation advertises exactly
> this to a guest.
>
> > Is it actually possible
> > to find hardware that supports 4K but with an ITS that only support 64K
> > or 16K pages? It seems insane to me. Otherwise can't we probe the page
> > size somehow?
>
> We can probe by writing and seeing if it sticks - that's what the code
> does. Is it really so horrible? I agree it's nasty, but isn't it
> basically a loop around the code needed anyway?
It looks very strange that there isn't a better way to find that info.
It looks a bit like an hack. It is also bad from a software point of
view being forced to cope with all three possible page granularities.
But oh well, sometimes we just have to deal with whatever the hardware
offers us.
> Yes to the rest of the comments.
>
>
> >> + for (pagesz = 0; pagesz < 3; pagesz++)
> >> + {
> >> + uint64_t reg;
> >> + int nr_bytes;
> >> +
> >> + nr_bytes = ROUNDUP(nr_items * entry_size, BIT(pagesz * 2 + 12));
> >> + 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;
> >> + }
> >> + }
> >> +
> >> + 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 < 8; i++)
> >
> > Code style. Unfortunately we don't have a script to check, but please
> > refer to CODING_STYLE. I'd prefer if every number was #define'ed,
> > including `8' (something like GITS_BASER_MAX).
> >
> >
> >> + {
> >> + void __iomem *basereg = hw_its->its_base + GITS_BASER0 + i * 8;
> >> + int type;
> >> +
> >> + reg = readq_relaxed(basereg);
> >> + type = (reg >> 56) & 0x7;
> >
> > Please #define 56 and 0x7
> >
> >
> >> + switch ( type )
> >> + {
> >> + case GITS_BASER_TYPE_NONE:
> >> + continue;
> >> + case GITS_BASER_TYPE_DEVICE:
> >> + /* TODO: find some better way of limiting the number of
> >> devices */
> >> + gicv3_map_baser(basereg, reg, 1024);
> >
> > An hardcoded max value might be OK, but please #define it.
> >
> >
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |