[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.