[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v3 10/18] xen/arm: ITS: Add APIs to add and assign device
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> Add APIs to add devices to RB-tree, assign and remove devices to domain. Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> --- xen/arch/arm/gic-v3-its.c | 246 ++++++++++++++++++++++++++++++++++++++++- xen/include/asm-arm/gic-its.h | 4 +- 2 files changed, 246 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 2a4fa97..4471669 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -94,6 +94,7 @@ static LIST_HEAD(its_nodes); static DEFINE_SPINLOCK(its_lock); static struct rdist_prop *gic_rdists; static struct rb_root rb_its_dev; +static DEFINE_SPINLOCK(rb_its_dev_lock); #define gic_data_rdist() (per_cpu(rdist, smp_processor_id())) #define gic_data_rdist_rd_base() (per_cpu(rdist, smp_processor_id()).rbase) @@ -152,6 +153,21 @@ u32 its_get_nr_events(void) return (1 << id_bits); } +static struct its_node * its_get_phys_node(u32 dev_id) +{ + struct its_node *its; + + /* TODO: For now return ITS0 node. + * Need Query PCI helper function to get on which + * ITS node the device is attached + */ + list_for_each_entry(its, &its_nodes, entry) + { + return its; + } + + return NULL; +} /* RB-tree helpers for its_device */ struct its_device * find_its_device(struct rb_root *root, u32 devid) { @@ -459,7 +475,7 @@ void its_send_inv(struct its_device *dev, struct its_collection *col, its_send_single_command(dev->its, its_build_inv_cmd, &desc); } -void its_send_mapd(struct its_device *dev, int valid) +static void its_send_mapd(struct its_device *dev, int valid) { struct its_cmd_desc desc; @@ -493,7 +509,7 @@ void its_send_mapvi(struct its_device *dev, struct its_collection *col, its_send_single_command(dev->its, its_build_mapvi_cmd, &desc); } -void its_send_movi(struct its_device *dev, struct its_collection *col, +static void its_send_movi(struct its_device *dev, struct its_collection *col, u32 event) { struct its_cmd_desc desc; @@ -596,7 +612,7 @@ int its_lpi_init(u32 id_bits) return 0; } -unsigned long *its_lpi_alloc_chunks(int nirqs, int *base, int *nr_ids) +static unsigned long *its_lpi_alloc_chunks(int nirqs, int *base, int *nr_ids) { unsigned long *bitmap = NULL; int chunk_id; @@ -636,6 +652,230 @@ out: return bitmap; } +static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids) +{ + int lpi; + + spin_lock(&lpi_lock); + + for ( lpi = base; lpi < (base + nr_ids); lpi += IRQS_PER_CHUNK ) + { + int chunk = its_lpi_to_chunk(lpi); + + BUG_ON(chunk > lpi_chunks); + if ( test_bit(chunk, lpi_bitmap) ) + clear_bit(chunk, lpi_bitmap); + else + its_err("Bad LPI chunk %d\n", chunk); + } + + spin_unlock(&lpi_lock); + + xfree(bitmap); +} + +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 = dev->lpi_base + idx; + set_bit(idx, dev->lpi_map); + + return 0; +} + +static u32 its_get_plpi(struct its_device *dev, u32 event) +{ + ASSERT(event < dev->nr_lpis); + return dev->lpi_base + event; +} + +/* Device assignment. Should be called from pci_device_add */ +int its_add_device(struct domain *d, u32 devid) +{ + struct its_device *dev; + unsigned long *lpi_map; + void *itt; + int lpi_base, nr_lpis, sz; + u32 i, nr_ites, plpi, nr_cpus; + struct its_collection *col; + + spin_lock(&rb_its_dev_lock); + dev = find_its_device(&rb_its_dev, devid); + if ( dev ) + { + spin_unlock(&rb_its_dev_lock); + dprintk(XENLOG_G_ERR, "ITS:d%dv%d Device already exists dev 0x%x\n", + d->domain_id, current->vcpu_id, dev->device_id); + return -EEXIST; + } + spin_unlock(&rb_its_dev_lock); + + DPRINTK("ITS:d%dv%d Add device devid 0x%x\n", + d->domain_id, current->vcpu_id, devid); + + dev = xzalloc(struct its_device); + if ( dev == NULL ) + return -ENOMEM; + + dev->its = its_get_phys_node(devid); + /* TODO: Use pci helper to get nvecs */ + nr_ites = 64; + sz = nr_ites * dev->its->ite_size; + sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; + itt = xzalloc_bytes(sz); + if ( !itt ) + return -ENOMEM; + + lpi_map = its_lpi_alloc_chunks(nr_ites, &lpi_base, &nr_lpis); + if ( !lpi_map || (nr_lpis != nr_ites) ) + { + xfree(dev); + xfree(itt); + xfree(lpi_map); + return -EINVAL; + } + + dev->itt_addr = (u64)itt; + dev->nr_ites = nr_ites; + dev->lpi_map = lpi_map; + dev->lpi_base = lpi_base; + /* nr_lpis should be always equal to nvecs */ + dev->nr_lpis = nr_lpis; + dev->device_id = devid; + + DPRINTK("ITS:d%dv%d Adding Device with id 0x%x nvecs %d lpi_base 0x%x\n", + d->domain_id, current->vcpu_id, dev->device_id, + dev->nr_lpis, dev->lpi_base); + + /* Map device to its ITT */ + its_send_mapd(dev, 1); + + nr_cpus = num_online_cpus(); + for ( i = 0; i < nr_ites; i++ ) + { + /* Reserve pLPI */ + if ( its_alloc_device_irq(dev, &plpi) ) + return -ENOSPC; + + /* For each pLPI send MAPVI command */ + col = &dev->its->collections[(i % nr_cpus)]; + its_send_mapvi(dev, col, plpi, i); + } + + spin_lock(&rb_its_dev_lock); + if ( insert_its_device(&rb_its_dev, dev) ) + { + spin_unlock(&rb_its_dev_lock); + return -EINVAL; + } + spin_unlock(&rb_its_dev_lock); + + return 0; +} + +int its_assign_device(struct domain *d, u32 vdevid) +{ + struct its_device *pdev; + struct vits_device *vdev; + struct irq_desc *desc; + u32 plpi, i, pdevid; + + DPRINTK("ITS:d%dv%d Assign request for virtual device 0x%x\n", + d->domain_id, current->vcpu_id, vdevid); + vdev = find_vits_device(&d->arch.vits->dev_root, vdevid); + if ( vdev ) + return -ENODEV; + + /* TODO: Use PCI helper to convert vDevid to pDevid */ + pdevid = vdevid; + spin_lock(&rb_its_dev_lock); + pdev = find_its_device(&rb_its_dev, pdevid); + if ( !pdev ) + { + spin_unlock(&rb_its_dev_lock); + return -ENODEV; + } + spin_unlock(&rb_its_dev_lock); + + vdev = xzalloc_bytes(sizeof(struct vits_device)); + if ( !pdev ) + return -ENOMEM; + + vdev->its_dev = pdev; + vdev->vdevid = vdevid; + vdev->pdevid = pdevid; + + /* Insert to domains' list */ + if ( insert_vits_device(&d->arch.vits->dev_root, vdev) ) + return -EINVAL; + + DPRINTK("ITS:d%dv%d Assign pdevid 0x%x with nvecs %d\n", + d->domain_id, current->vcpu_id, pdev->device_id, pdev->nr_lpis); + + /* XXX: Event id always starts from 0? */ + for ( i = 0; i < pdev->nr_lpis; i++ ) + { + plpi = its_get_plpi(pdev, i); + route_irq_to_guest(d, i, plpi, "LPI"); + /* Enable all the event in LPI configuration table */ + desc = irq_to_desc(plpi); + set_irq_device(desc, pdev); + lpi_set_config(desc, 1); + } + + return 0; +} + +int its_detach_device(struct domain *d, u32 vdevid) +{ + struct its_device *pdev; + struct vits_device *vdev; + struct irq_desc *desc; + u32 plpi, i, pdevid; + + DPRINTK("ITS:d%dv%d Detach request for virtual device 0x%x\n", + d->domain_id, current->vcpu_id, vdevid); + vdev = find_vits_device(&d->arch.vits->dev_root, vdevid); + if ( !vdev ) + return -EINVAL; + + /* XXX: convert vDevid to pDevid ? */ + pdevid = vdevid; + spin_lock(&rb_its_dev_lock); + pdev = find_its_device(&rb_its_dev, pdevid); + if ( !pdev ) + { + spin_unlock(&rb_its_dev_lock); + return -EINVAL; + } + spin_unlock(&rb_its_dev_lock); + + DPRINTK("ITS:d%dv%d Detach pdevid 0x%x with nvecs %d\n", + d->domain_id, current->vcpu_id, pdev->device_id, pdev->nr_lpis); + /* Remove vits_device from domain list */ + remove_vits_device(&d->arch.vits->dev_root, vdev); + xfree(vdev); + + for ( i = 0; i < pdev->nr_lpis; i++ ) + { + plpi = its_get_plpi(pdev, i); + /* XXX: Event id always starts from 0 */ + release_irq(plpi, d); + /* Disable all the event in LPI configuration table */ + desc = irq_to_desc(plpi); + set_irq_device(desc, NULL); + lpi_set_config(desc, 0); + } + + its_lpi_free(pdev->lpi_map, pdev->lpi_base, pdev->nr_lpis); + + 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/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h index a1099a1..8f898a6 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -263,7 +263,9 @@ static inline uint32_t its_decode_devid(struct domain *d, its_cmd_block *cmd) void its_set_affinity(struct irq_desc *desc, int cpu); void lpi_set_config(struct irq_desc *desc, int enable); uint32_t its_get_nr_events(void); - +struct vits_device * find_vits_device(struct rb_root *root, uint32_t devid); +int insert_vits_device(struct rb_root *root, struct vits_device *dev); +int remove_vits_device(struct rb_root *root, struct vits_device *dev); #endif /* __ASM_ARM_GIC_ITS_H__ */ /* -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |