diff mbox

[05/28] ARM: GICv3 ITS: map ITS command buffer

Message ID 20170130183153.28566-6-andre.przywara@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andre Przywara Jan. 30, 2017, 6:31 p.m. UTC
Instead of directly manipulating the tables in memory, an ITS driver
sends commands via a ring buffer to the ITS h/w to create or alter the
LPI mappings.
Allocate memory for that buffer and tell the ITS about it to be able
to send ITS commands.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v3-its.c        | 46 ++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic_v3_its.h |  6 ++++++
 2 files changed, 52 insertions(+)

Comments

Julien Grall Feb. 6, 2017, 5:43 p.m. UTC | #1
Hi Andre,

On 30/01/17 18:31, Andre Przywara wrote:
> Instead of directly manipulating the tables in memory, an ITS driver
> sends commands via a ring buffer to the ITS h/w to create or alter the
> LPI mappings.
> Allocate memory for that buffer and tell the ITS about it to be able
> to send ITS commands.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/gic-v3-its.c        | 46 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/gic_v3_its.h |  6 ++++++
>  2 files changed, 52 insertions(+)
>
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index c31fef6..ad7cd2a 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -27,6 +27,8 @@
>  #include <asm/gic_v3_its.h>
>  #include <asm/io.h>
>
> +#define ITS_CMD_QUEUE_SZ                SZ_64K
> +
>  #define BASER_ATTR_MASK                                           \
>          ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT)               | \
>           (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)         | \
> @@ -44,6 +46,45 @@ static uint64_t encode_phys_addr(paddr_t addr, int page_bits)
>      return ret | (addr & GENMASK(51, 48)) >> (48 - 12);
>  }
>
> +static void *its_map_cbaser(struct host_its *its)
> +{
> +    void __iomem *cbasereg = its->its_base + GITS_CBASER;
> +    uint64_t reg, regc;
> +    void *buffer;
> +    paddr_t paddr;
> +
> +    reg  = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
> +    reg |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
> +    reg |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
> +
> +    buffer = _xzalloc(ITS_CMD_QUEUE_SZ, PAGE_SIZE);

s/PAGE_SIZE/SZ_4K/

> +    if ( !buffer )
> +        return NULL;
> +    paddr = virt_to_maddr(buffer);
> +    ASSERT(!(paddr & ~GENMASK(51, 12)));

Please remove the ASSERT (see why on patch #3).

> +
> +    reg |= GITS_VALID_BIT | paddr;
> +    reg |= ((ITS_CMD_QUEUE_SZ / PAGE_SIZE) - 1) & GITS_CBASER_SIZE_MASK;
> +    writeq_relaxed(reg, cbasereg);
> +    regc = readq_relaxed(cbasereg);

You could re-use reg rather than introduce a new variable regc. This 
would avoid some confusion on which one to use.

> +
> +    /* If the ITS dropped shareability, drop cacheability as well. */
> +    if ( (regc & GITS_BASER_SHAREABILITY_MASK) == 0 )
> +    {
> +        regc &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
> +        writeq_relaxed(regc, cbasereg);
> +    }
> +
> +    /*
> +     * If the command queue memory is mapped as uncached, we need to flush
> +     * it on every access.
> +     */
> +    if ( !(regc & GITS_BASER_INNER_CACHEABILITY_MASK) )
> +        its->flags |= HOST_ITS_FLUSH_CMD_QUEUE;

Could you add a print to inform the user about the cache flush? It is 
something quite useful to know in the log.

> +
> +    return buffer;
> +}
> +
>  #define PAGE_BITS(sz) ((sz) * 2 + PAGE_SHIFT)
>
>  static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items)
> @@ -150,6 +191,11 @@ int gicv3_its_init(struct host_its *hw_its)
>          }
>      }
>
> +    hw_its->cmd_buf = its_map_cbaser(hw_its);
> +    if ( !hw_its->cmd_buf )
> +        return -ENOMEM;
> +    writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
> +
>      return 0;
>  }
>
> diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
> index ed44bdb..ff5572f 100644
> --- a/xen/include/asm-arm/gic_v3_its.h
> +++ b/xen/include/asm-arm/gic_v3_its.h
> @@ -65,9 +65,13 @@
>  #define GITS_BASER_OUTER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)
>  #define GITS_BASER_INNER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT)
>
> +#define GITS_CBASER_SIZE_MASK           0xff
> +
>  #ifndef __ASSEMBLY__
>  #include <xen/device_tree.h>
>
> +#define HOST_ITS_FLUSH_CMD_QUEUE        (1U << 0)
> +
>  /* data structure for each hardware ITS */
>  struct host_its {
>      struct list_head entry;
> @@ -75,6 +79,8 @@ struct host_its {
>      paddr_t addr;
>      paddr_t size;
>      void __iomem *its_base;
> +    void *cmd_buf;
> +    unsigned int flags;
>  };
>
>  extern struct list_head host_its_list;
>

Regards,
Stefano Stabellini Feb. 14, 2017, 12:59 a.m. UTC | #2
On Mon, 30 Jan 2017, Andre Przywara wrote:
> Instead of directly manipulating the tables in memory, an ITS driver
> sends commands via a ring buffer to the ITS h/w to create or alter the
> LPI mappings.
> Allocate memory for that buffer and tell the ITS about it to be able
> to send ITS commands.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  xen/arch/arm/gic-v3-its.c        | 46 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/gic_v3_its.h |  6 ++++++
>  2 files changed, 52 insertions(+)
> 
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index c31fef6..ad7cd2a 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -27,6 +27,8 @@
>  #include <asm/gic_v3_its.h>
>  #include <asm/io.h>
>  
> +#define ITS_CMD_QUEUE_SZ                SZ_64K
> +
>  #define BASER_ATTR_MASK                                           \
>          ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT)               | \
>           (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)         | \
> @@ -44,6 +46,45 @@ static uint64_t encode_phys_addr(paddr_t addr, int page_bits)
>      return ret | (addr & GENMASK(51, 48)) >> (48 - 12);
>  }
>  
> +static void *its_map_cbaser(struct host_its *its)
> +{
> +    void __iomem *cbasereg = its->its_base + GITS_CBASER;
> +    uint64_t reg, regc;
> +    void *buffer;
> +    paddr_t paddr;
> +
> +    reg  = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
> +    reg |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
> +    reg |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
> +
> +    buffer = _xzalloc(ITS_CMD_QUEUE_SZ, PAGE_SIZE);
> +    if ( !buffer )
> +        return NULL;
> +    paddr = virt_to_maddr(buffer);
> +    ASSERT(!(paddr & ~GENMASK(51, 12)));
> +
> +    reg |= GITS_VALID_BIT | paddr;
> +    reg |= ((ITS_CMD_QUEUE_SZ / PAGE_SIZE) - 1) & GITS_CBASER_SIZE_MASK;
> +    writeq_relaxed(reg, cbasereg);
> +    regc = readq_relaxed(cbasereg);
> +
> +    /* If the ITS dropped shareability, drop cacheability as well. */
> +    if ( (regc & GITS_BASER_SHAREABILITY_MASK) == 0 )
> +    {
> +        regc &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
> +        writeq_relaxed(regc, cbasereg);
> +    }
> +
> +    /*
> +     * If the command queue memory is mapped as uncached, we need to flush
> +     * it on every access.
> +     */
> +    if ( !(regc & GITS_BASER_INNER_CACHEABILITY_MASK) )
> +        its->flags |= HOST_ITS_FLUSH_CMD_QUEUE;
> +
> +    return buffer;
> +}
> +
>  #define PAGE_BITS(sz) ((sz) * 2 + PAGE_SHIFT)
>  
>  static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items)
> @@ -150,6 +191,11 @@ int gicv3_its_init(struct host_its *hw_its)
>          }
>      }
>  
> +    hw_its->cmd_buf = its_map_cbaser(hw_its);
> +    if ( !hw_its->cmd_buf )
> +        return -ENOMEM;
> +    writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
 
Why this new write?
Julien Grall Feb. 14, 2017, 8:50 p.m. UTC | #3
Hi Stefano,

On 02/14/2017 12:59 AM, Stefano Stabellini wrote:
> On Mon, 30 Jan 2017, Andre Przywara wrote:
>>  static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items)
>> @@ -150,6 +191,11 @@ int gicv3_its_init(struct host_its *hw_its)
>>          }
>>      }
>>
>> +    hw_its->cmd_buf = its_map_cbaser(hw_its);
>> +    if ( !hw_its->cmd_buf )
>> +        return -ENOMEM;
>> +    writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
>
> Why this new write?

This was requested by me. From the spec (8.19.5 in ARM IHI 0069C), the
reset value of GITS_CWRITER is unknown. So we have to reset the register
to 0 otherwise the ITS may try to read invalid command as soon as it has
been enabled.

FWIW, GITS_CREADR was reset to 0 by the ITS when GITS_CBASER has
successfully been written (see 8.19.2).

Cheers,

--
Julien Grall
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Stefano Stabellini Feb. 14, 2017, 9 p.m. UTC | #4
On Tue, 14 Feb 2017, Julien Grall wrote:
> Hi Stefano,
> 
> On 02/14/2017 12:59 AM, Stefano Stabellini wrote:
> > On Mon, 30 Jan 2017, Andre Przywara wrote:
> > >  static int its_map_baser(void __iomem *basereg, uint64_t regc, int
> > > nr_items)
> > > @@ -150,6 +191,11 @@ int gicv3_its_init(struct host_its *hw_its)
> > >          }
> > >      }
> > > 
> > > +    hw_its->cmd_buf = its_map_cbaser(hw_its);
> > > +    if ( !hw_its->cmd_buf )
> > > +        return -ENOMEM;
> > > +    writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
> > 
> > Why this new write?
> 
> This was requested by me. From the spec (8.19.5 in ARM IHI 0069C), the
> reset value of GITS_CWRITER is unknown. So we have to reset the register
> to 0 otherwise the ITS may try to read invalid command as soon as it has
> been enabled.
> 
> FWIW, GITS_CREADR was reset to 0 by the ITS when GITS_CBASER has
> successfully been written (see 8.19.2).

All right, thanks
diff mbox

Patch

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index c31fef6..ad7cd2a 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -27,6 +27,8 @@ 
 #include <asm/gic_v3_its.h>
 #include <asm/io.h>
 
+#define ITS_CMD_QUEUE_SZ                SZ_64K
+
 #define BASER_ATTR_MASK                                           \
         ((0x3UL << GITS_BASER_SHAREABILITY_SHIFT)               | \
          (0x7UL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)         | \
@@ -44,6 +46,45 @@  static uint64_t encode_phys_addr(paddr_t addr, int page_bits)
     return ret | (addr & GENMASK(51, 48)) >> (48 - 12);
 }
 
+static void *its_map_cbaser(struct host_its *its)
+{
+    void __iomem *cbasereg = its->its_base + GITS_CBASER;
+    uint64_t reg, regc;
+    void *buffer;
+    paddr_t paddr;
+
+    reg  = GIC_BASER_InnerShareable << GITS_BASER_SHAREABILITY_SHIFT;
+    reg |= GIC_BASER_CACHE_SameAsInner << GITS_BASER_OUTER_CACHEABILITY_SHIFT;
+    reg |= GIC_BASER_CACHE_RaWaWb << GITS_BASER_INNER_CACHEABILITY_SHIFT;
+
+    buffer = _xzalloc(ITS_CMD_QUEUE_SZ, PAGE_SIZE);
+    if ( !buffer )
+        return NULL;
+    paddr = virt_to_maddr(buffer);
+    ASSERT(!(paddr & ~GENMASK(51, 12)));
+
+    reg |= GITS_VALID_BIT | paddr;
+    reg |= ((ITS_CMD_QUEUE_SZ / PAGE_SIZE) - 1) & GITS_CBASER_SIZE_MASK;
+    writeq_relaxed(reg, cbasereg);
+    regc = readq_relaxed(cbasereg);
+
+    /* If the ITS dropped shareability, drop cacheability as well. */
+    if ( (regc & GITS_BASER_SHAREABILITY_MASK) == 0 )
+    {
+        regc &= ~GITS_BASER_INNER_CACHEABILITY_MASK;
+        writeq_relaxed(regc, cbasereg);
+    }
+
+    /*
+     * If the command queue memory is mapped as uncached, we need to flush
+     * it on every access.
+     */
+    if ( !(regc & GITS_BASER_INNER_CACHEABILITY_MASK) )
+        its->flags |= HOST_ITS_FLUSH_CMD_QUEUE;
+
+    return buffer;
+}
+
 #define PAGE_BITS(sz) ((sz) * 2 + PAGE_SHIFT)
 
 static int its_map_baser(void __iomem *basereg, uint64_t regc, int nr_items)
@@ -150,6 +191,11 @@  int gicv3_its_init(struct host_its *hw_its)
         }
     }
 
+    hw_its->cmd_buf = its_map_cbaser(hw_its);
+    if ( !hw_its->cmd_buf )
+        return -ENOMEM;
+    writeq_relaxed(0, hw_its->its_base + GITS_CWRITER);
+
     return 0;
 }
 
diff --git a/xen/include/asm-arm/gic_v3_its.h b/xen/include/asm-arm/gic_v3_its.h
index ed44bdb..ff5572f 100644
--- a/xen/include/asm-arm/gic_v3_its.h
+++ b/xen/include/asm-arm/gic_v3_its.h
@@ -65,9 +65,13 @@ 
 #define GITS_BASER_OUTER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_OUTER_CACHEABILITY_SHIFT)
 #define GITS_BASER_INNER_CACHEABILITY_MASK   (0x7ULL << GITS_BASER_INNER_CACHEABILITY_SHIFT)
 
+#define GITS_CBASER_SIZE_MASK           0xff
+
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
 
+#define HOST_ITS_FLUSH_CMD_QUEUE        (1U << 0)
+
 /* data structure for each hardware ITS */
 struct host_its {
     struct list_head entry;
@@ -75,6 +79,8 @@  struct host_its {
     paddr_t addr;
     paddr_t size;
     void __iomem *its_base;
+    void *cmd_buf;
+    unsigned int flags;
 };
 
 extern struct list_head host_its_list;