From mboxrd@z Thu Jan 1 00:00:00 1970 From: vijay.kilari@gmail.com Subject: [PATCH v5 19/22] xen/arm: ITS: Add APIs to add and assign device Date: Mon, 27 Jul 2015 16:42:01 +0530 Message-ID: <1437995524-19772-20-git-send-email-vijay.kilari@gmail.com> References: <1437995524-19772-1-git-send-email-vijay.kilari@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1437995524-19772-1-git-send-email-vijay.kilari@gmail.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Ian.Campbell@citrix.com, julien.grall@citrix.com, stefano.stabellini@eu.citrix.com, stefano.stabellini@citrix.com, tim@xen.org, xen-devel@lists.xen.org Cc: Prasun.Kapoor@caviumnetworks.com, manish.jaggi@caviumnetworks.com, Vijaya Kumar K , vijay.kilari@gmail.com List-Id: xen-devel@lists.xenproject.org From: Vijaya Kumar K Add APIs to add devices to RB-tree, assign and remove devices to domain. Signed-off-by: Vijaya Kumar K --- v5: - Removed its_detach_device API - Pass nr_ites as parameter to its_add_device v4: - Introduced helper to populate its_device struct - Fixed freeing of its_device memory - its_device struct holds domain id --- xen/arch/arm/gic-v3-its.c | 224 +++++++++++++++++++++++++++++++++++++++-- xen/arch/arm/irq.c | 8 ++ xen/include/asm-arm/gic-its.h | 2 + xen/include/asm-arm/irq.h | 1 + 4 files changed, 226 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 0d8582a..99f6edc 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -115,8 +115,21 @@ u32 its_get_nr_event_ids(void) return (1 << its_data.eventid_bits); } +static struct its_node *its_get_phys_node(struct dt_device_node *dt) +{ + struct its_node *its; + + list_for_each_entry(its, &its_nodes, entry) + { + if ( its->dt_node == dt ) + return its; + } + + return NULL; +} + /* RB-tree helpers for its_device */ -struct its_device *its_find_device(u32 devid) +static struct its_device *its_find_device(u32 devid) { struct rb_node *node = rb_its_dev.rb_node; @@ -137,7 +150,7 @@ struct its_device *its_find_device(u32 devid) return NULL; } -int its_insert_device(struct its_device *dev) +static int its_insert_device(struct its_device *dev) { struct rb_node **new, *parent; @@ -319,7 +332,7 @@ static void its_send_inv(struct its_device *dev, struct its_collection *col, its_send_single_command(dev->its, &cmd, col); } -void its_send_mapd(struct its_device *dev, int valid) +static void its_send_mapd(struct its_device *dev, int valid) { its_cmd_block cmd; unsigned long itt_addr; @@ -357,8 +370,8 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col, its_send_single_command(its, &cmd, col); } -void its_send_mapvi(struct its_device *dev, struct its_collection *col, - u32 phys_id, u32 event) +static void its_send_mapvi(struct its_device *dev, struct its_collection *col, + u32 phys_id, u32 event) { its_cmd_block cmd; @@ -383,8 +396,8 @@ static void its_send_invall(struct its_node *its, struct its_collection *col) its_send_single_command(its, &cmd, NULL); } -void its_send_discard(struct its_device *dev, struct its_collection *col, - u32 event) +static void its_send_discard(struct its_device *dev, struct its_collection *col, + u32 event) { its_cmd_block cmd; @@ -573,7 +586,7 @@ static int its_lpi_init(u32 id_bits) return 0; } -unsigned long *its_lpi_alloc_chunks(int nirqs, int *base) +static unsigned long *its_lpi_alloc_chunks(int nirqs, int *base) { unsigned long *bitmap = NULL; int chunk_id, nr_chunks, nr_ids, i; @@ -617,7 +630,7 @@ out: return bitmap; } -void its_lpi_free(struct its_device *dev) +static void its_lpi_free(struct its_device *dev) { int lpi; @@ -639,6 +652,199 @@ void its_lpi_free(struct its_device *dev) xfree(dev->lpi_map); } +static void its_discard_lpis(struct its_device *dev, u32 ids) +{ + struct its_collection *col; + int i; + + for ( i = 0; i < ids; i++) + { + col = &dev->its->collections[(i % nr_cpu_ids)]; + its_send_discard(dev, col, i); + } +} + +static inline u32 its_get_plpi(struct its_device *dev, u32 event) +{ + return dev->lpi_base + event; +} + +static int its_alloc_device_irq(struct its_device *dev, u32 *hwirq) +{ + int idx; + + idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis); + if ( idx == dev->nr_lpis ) + return -ENOSPC; + + *hwirq = its_get_plpi(dev, idx); + set_bit(idx, dev->lpi_map); + + return 0; +} + +static void its_free_device(struct its_device *dev) +{ + xfree(dev->itt_addr); + xfree(dev->lpi_map); + xfree(dev); +} + +static struct its_device *its_alloc_device(u32 devid, u32 nr_ites, + struct dt_device_node *dt_its) +{ + struct its_device *dev; + paddr_t *itt; + unsigned long *lpi_map; + int lpi_base, sz; + + dev = xzalloc(struct its_device); + if ( dev == NULL ) + return NULL; + + dev->its = its_get_phys_node(dt_its); + if (dev->its == NULL) + { + dprintk(XENLOG_G_ERR, "ITS: Failed to find ITS node 0x%"PRIx32"\n", + devid); + goto err; + } + + sz = nr_ites * dev->its->ite_size; + sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; + itt = xzalloc_bytes(sz); + if ( !itt ) + goto err; + + lpi_map = its_lpi_alloc_chunks(nr_ites, &lpi_base); + if ( !lpi_map ) + goto lpi_err; + + dev->itt_addr = itt; + dev->lpi_map = lpi_map; + dev->lpi_base = lpi_base; + dev->nr_lpis = nr_ites; + dev->device_id = devid; + + return dev; + +lpi_err: + xfree(itt); + xfree(lpi_map); +err: + xfree(dev); + + return NULL; +} + +/* Device assignment */ +int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its) +{ + struct its_device *dev; + u32 i, plpi = 0; + struct its_collection *col; + struct irq_desc *desc; + struct msi_desc *msi = NULL; + int res = 0; + + spin_lock(&rb_its_dev_lock); + dev = its_find_device(devid); + if ( dev ) + { + dprintk(XENLOG_G_ERR, "ITS: Device already exists 0x%"PRIx32"\n", + dev->device_id); + res = -EEXIST; + goto err; + } + + dev = its_alloc_device(devid, nr_ites, dt_its); + if ( !dev ) + { + res = -ENOMEM; + goto err; + } + + if ( its_insert_device(dev) ) + { + its_free_device(dev); + dprintk(XENLOG_G_ERR, "ITS: failed to insert device 0x%"PRIx32"\n", + devid); + res = -EINVAL; + goto err; + } + + DPRINTK("ITS:Add Device 0x%"PRIx32" lpis %"PRId32" base 0x%"PRIx32"\n", + dev->device_id, dev->nr_lpis, dev->lpi_base); + + /* Map device to its ITT */ + its_send_mapd(dev, 1); + + for ( i = 0; i < dev->nr_lpis; i++ ) + { + msi = xzalloc(struct msi_desc); + /* Reserve pLPI */ + if ( its_alloc_device_irq(dev, &plpi) || !msi ) + { + its_discard_lpis(dev, i); + its_lpi_free(dev); + its_send_mapd(dev, 0); + its_free_device(dev); + dprintk(XENLOG_G_ERR,"ITS: Cannot add device 0x%"PRIx32"\n", devid); + res = -ENOSPC; + goto err; + } + + /* For each pLPI send MAPVI command */ + col = &dev->its->collections[(i % nr_cpu_ids)]; + /* Store collection for this plpi in irq_desc */ + desc = irq_to_desc(plpi); + spin_lock(&desc->lock); + desc->msi_desc = msi; + set_lpi_event(desc, i); + set_irq_its_device(desc, dev); + irqdesc_set_collection(desc, col->col_id); + spin_unlock(&desc->lock); + its_send_mapvi(dev, col, plpi, i); + } + +err: + spin_unlock(&rb_its_dev_lock); + + return res; +} + +int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid) +{ + struct its_device *pdev; + u32 plpi, i; + + DPRINTK("ITS: Assign request for dev 0x%"PRIx32" to domain %"PRId32"\n", + vdevid, d->domain_id); + + spin_lock(&rb_its_dev_lock); + pdev = its_find_device(pdevid); + if ( !pdev ) + { + spin_unlock(&rb_its_dev_lock); + return -ENODEV; + } + spin_unlock(&rb_its_dev_lock); + + pdev->domain_id = d->domain_id; + pdev->virt_device_id = vdevid; + + DPRINTK("ITS: Assign pdevid 0x%"PRIx32" lpis %"PRId32" for dom %"PRId32"\n", + pdevid, pdev->nr_lpis, d->domain_id); + + for ( i = 0; i < pdev->nr_lpis; i++ ) + { + plpi = its_get_plpi(pdev, i); + /* TODO: Route lpi */ + } + + return 0; +} + /* * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to * deal with (one configuration byte per interrupt). PENDBASE has to diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index ae301a4..f217c35 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -163,6 +163,14 @@ unsigned int irq_to_virq(struct irq_desc *desc) } #ifdef HAS_GICV3 +void set_lpi_event(struct irq_desc *desc, unsigned id) +{ + ASSERT(spin_is_locked(&desc->lock)); + ASSERT(desc->msi_desc != NULL); + + desc->msi_desc->eventID = id; +} + unsigned int irq_to_vid(struct irq_desc *desc) { ASSERT(desc->msi_desc != NULL); diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h index da689a4..77f694f 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -369,6 +369,8 @@ void its_set_lpi_properties(struct irq_desc *desc, unsigned int priority); int vits_domain_init(struct domain *d); void vits_domain_free(struct domain *d); +int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its); +int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid); int vits_get_vitt_entry(struct domain *d, uint32_t devid, uint32_t event, struct vitt *entry); int vits_get_vdevice_entry(struct domain *d, uint32_t devid, diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 00d5345..b4ac8bb 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -61,6 +61,7 @@ void arch_move_irqs(struct vcpu *v); /* Set IRQ type for an SPI */ int irq_set_spi_type(unsigned int spi, unsigned int type); +void set_lpi_event(struct irq_desc *desc, unsigned id); unsigned int irq_to_virq(struct irq_desc *desc); unsigned int irq_to_vid(struct irq_desc *desc); struct its_device *get_irq_its_device(struct irq_desc *desc); -- 1.7.9.5