[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> This patch just makes ITS driver taken from linux compiles in xen environment. The following changes are done - memory allocation apis are changed - raw spin lock api's changed to normal spin lock api's - debug prints changed to xen debug prints - remove msi chip functions to setup_irq and teardown_irq - linux irqchip functions are removed - updated gic_v3_defs.h file Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> --- xen/arch/arm/Makefile | 1 + xen/arch/arm/gic-v3-its.c | 548 +++++++++++++------------------------ xen/arch/arm/gic-v3.c | 1 + xen/include/asm-arm/gic_v3_defs.h | 127 +++++++++ 4 files changed, 322 insertions(+), 355 deletions(-) diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 41aba2e..f6eb834 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -13,6 +13,7 @@ obj-y += sysctl.o obj-y += domain_build.o obj-y += gic.o gic-v2.o obj-$(CONFIG_ARM_64) += gic-v3.o +obj-$(CONFIG_ARM_64) += gic-v3-its.o obj-y += io.o obj-y += irq.o obj-y += kernel.o diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 28b72e4..cde0ec0 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -2,6 +2,10 @@ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved. * Author: Marc Zyngier <marc.zyngier@xxxxxxx> * + * Xen changes: + * Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> + * Copyright (C) 2014, 2015 Cavium Inc. + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -15,28 +19,40 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <linux/bitmap.h> -#include <linux/cpu.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/log2.h> -#include <linux/mm.h> -#include <linux/msi.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_pci.h> -#include <linux/of_platform.h> -#include <linux/percpu.h> -#include <linux/slab.h> - -#include <linux/irqchip/arm-gic-v3.h> - -#include <asm/cacheflush.h> -#include <asm/cputype.h> -#include <asm/exception.h> - -#include "irqchip.h" +#include <xen/config.h> +#include <xen/lib.h> +#include <xen/init.h> +#include <xen/cpu.h> +#include <xen/mm.h> +#include <xen/irq.h> +#include <xen/sched.h> +#include <xen/errno.h> +#include <xen/delay.h> +#include <xen/device_tree.h> +#include <xen/libfdt/libfdt.h> +#include <xen/xmalloc.h> +#include <xen/list.h> +#include <xen/sizes.h> +#include <asm/p2m.h> +#include <asm/domain.h> +#include <asm/io.h> +#include <asm/device.h> +#include <asm/gic.h> +#include <asm/gic_v3_defs.h> + +#define its_print(lvl, fmt, ...) \ + printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__) + +#define its_err(fmt, ...) its_print(XENLOG_ERR, fmt, ## __VA_ARGS__) + +#define its_dbg(fmt, ...) \ + its_print(XENLOG_DEBUG, fmt, ## __VA_ARGS__) + +#define its_info(fmt, ...) \ + its_print(XENLOG_INFO, fmt, ## __VA_ARGS__) + +#define its_warn(fmt, ...) \ + its_print(XENLOG_WARNING, fmt, ## __VA_ARGS__) #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) @@ -58,9 +74,8 @@ struct its_collection { * devices writing to it. */ struct its_node { - raw_spinlock_t lock; + spinlock_t lock; struct list_head entry; - struct msi_chip msi_chip; void __iomem *base; unsigned long phys_base; struct its_cmd_block *cmd_base; @@ -92,12 +107,11 @@ struct its_device { static LIST_HEAD(its_nodes); static DEFINE_SPINLOCK(its_lock); -static struct irq_domain *lpi_domain; -static struct device_node *gic_root_node; -static struct rdists *gic_rdists; +static struct dt_device_node *gic_root_node; +static struct rdist_prop *gic_rdists; -#define gic_data_rdist() (raw_cpu_ptr(gic_rdists->rdist)) -#define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) +#define gic_data_rdist() (per_cpu(rdist, smp_processor_id())) +#define gic_data_rdist_rd_base() (per_cpu(rdist, smp_processor_id()).rbase) /* * ITS command descriptors - parameters to be encoded in a command @@ -228,10 +242,10 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd, struct its_cmd_desc *desc) { unsigned long itt_addr; - u8 size = max(order_base_2(desc->its_mapd_cmd.dev->nr_ites), 1); + u8 size = max(fls(desc->its_mapd_cmd.dev->nr_ites) - 1, 1); - itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt); - itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN); + itt_addr = __pa(desc->its_mapd_cmd.dev->itt); + itt_addr = ((itt_addr) + (ITS_ITT_ALIGN - 1)) & ~(ITS_ITT_ALIGN - 1); its_encode_cmd(cmd, GITS_CMD_MAPD); its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id); @@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its) static struct its_cmd_block *its_allocate_entry(struct its_node *its) { struct its_cmd_block *cmd; - u32 count = 1000000; /* 1s! */ + bool_t timeout = 0; + s_time_t deadline = NOW() + MILLISECS(1000); while (its_queue_full(its)) { - count--; - if (!count) { - pr_err_ratelimited("ITS queue not draining\n"); - return NULL; + if ( NOW() > deadline ) + { + timeout = 1; + break; } cpu_relax(); udelay(1); } + if ( timeout ) + { + its_err("ITS queue not draining\n"); + return NULL; + } cmd = its->cmd_write++; @@ -380,7 +400,7 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd) * the ITS. */ if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING) - __flush_dcache_area(cmd, sizeof(*cmd)); + clean_dcache_va_range(cmd, sizeof(*cmd)); else dsb(ishst); } @@ -390,7 +410,8 @@ static void its_wait_for_range_completion(struct its_node *its, struct its_cmd_block *to) { u64 rd_idx, from_idx, to_idx; - u32 count = 1000000; /* 1s! */ + bool_t timeout = 0; + s_time_t deadline = NOW() + MILLISECS(1000); from_idx = its_cmd_ptr_to_offset(its, from); to_idx = its_cmd_ptr_to_offset(its, to); @@ -400,14 +421,16 @@ static void its_wait_for_range_completion(struct its_node *its, if (rd_idx >= to_idx || rd_idx < from_idx) break; - count--; - if (!count) { - pr_err_ratelimited("ITS queue timeout\n"); - return; + if ( NOW() > deadline ) + { + timeout = 1; + break; } cpu_relax(); udelay(1); } + if ( timeout ) + printk("ITS queue timeout\n"); } static void its_send_single_command(struct its_node *its, @@ -417,12 +440,12 @@ static void its_send_single_command(struct its_node *its, struct its_cmd_block *cmd, *sync_cmd, *next_cmd; struct its_collection *sync_col; - raw_spin_lock(&its->lock); + spin_lock(&its->lock); cmd = its_allocate_entry(its); if (!cmd) { /* We're soooooo screewed... */ - pr_err_ratelimited("ITS can't allocate, dropping command\n"); - raw_spin_unlock(&its->lock); + its_err("ITS can't allocate, dropping command\n"); + spin_unlock(&its->lock); return; } sync_col = builder(cmd, desc); @@ -431,7 +454,7 @@ static void its_send_single_command(struct its_node *its, if (sync_col) { sync_cmd = its_allocate_entry(its); if (!sync_cmd) { - pr_err_ratelimited("ITS can't SYNC, skipping\n"); + its_warn("ITS can't SYNC, skipping\n"); goto post; } its_encode_cmd(sync_cmd, GITS_CMD_SYNC); @@ -442,12 +465,12 @@ static void its_send_single_command(struct its_node *its, post: next_cmd = its_post_commands(its); - raw_spin_unlock(&its->lock); + spin_unlock(&its->lock); its_wait_for_range_completion(its, cmd, next_cmd); } -static void its_send_inv(struct its_device *dev, u32 event_id) +void its_send_inv(struct its_device *dev, u32 event_id) { struct its_cmd_desc desc; @@ -489,7 +512,7 @@ static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id) its_send_single_command(dev->its, its_build_mapvi_cmd, &desc); } -static void its_send_movi(struct its_device *dev, +void its_send_movi(struct its_device *dev, struct its_collection *col, u32 id) { struct its_cmd_desc desc; @@ -501,7 +524,7 @@ static void its_send_movi(struct its_device *dev, its_send_single_command(dev->its, its_build_movi_cmd, &desc); } -static void its_send_discard(struct its_device *dev, u32 id) +void its_send_discard(struct its_device *dev, u32 id) { struct its_cmd_desc desc; @@ -521,104 +544,6 @@ static void its_send_invall(struct its_node *its, struct its_collection *col) } /* - * irqchip functions - assumes MSI, mostly. - */ - -static void lpi_set_config(struct its_device *its_dev, u32 hwirq, - u32 id, int enable) -{ - u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192; - - if (enable) - *cfg |= LPI_PROP_ENABLED; - else - *cfg &= ~LPI_PROP_ENABLED; - - /* - * Make the above write visible to the redistributors. - * And yes, we're flushing exactly: One. Single. Byte. - * Humpf... - */ - if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING) - __flush_dcache_area(cfg, sizeof(*cfg)); - else - dsb(ishst); - its_send_inv(its_dev, id); -} - -static inline u16 its_msi_get_entry_nr(struct msi_desc *desc) -{ - return desc->msi_attrib.entry_nr; -} - -static void its_mask_irq(struct irq_data *d) -{ - struct its_device *its_dev = irq_data_get_irq_handler_data(d); - u32 id; - - /* If MSI, propagate the mask to the RC */ - if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) { - id = its_msi_get_entry_nr(d->msi_desc); - mask_msi_irq(d); - } else { - id = d->hwirq; - } - - lpi_set_config(its_dev, d->hwirq, id, 0); -} - -static void its_unmask_irq(struct irq_data *d) -{ - struct its_device *its_dev = irq_data_get_irq_handler_data(d); - u32 id; - - /* If MSI, propagate the unmask to the RC */ - if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) { - id = its_msi_get_entry_nr(d->msi_desc); - unmask_msi_irq(d); - } else { - id = d->hwirq; - } - - lpi_set_config(its_dev, d->hwirq, id, 1); -} - -static void its_eoi_irq(struct irq_data *d) -{ - gic_write_eoir(d->hwirq); -} - -static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, - bool force) -{ - unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask); - struct its_device *its_dev = irq_data_get_irq_handler_data(d); - struct its_collection *target_col; - u32 id; - - if (cpu >= nr_cpu_ids) - return -EINVAL; - - target_col = &its_dev->its->collections[cpu]; - if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) - id = its_msi_get_entry_nr(d->msi_desc); - else - id = d->hwirq; - its_send_movi(its_dev, target_col, id); - its_dev->collection = target_col; - - return IRQ_SET_MASK_OK; -} - -static struct irq_chip its_irq_chip = { - .name = "ITS", - .irq_mask = its_mask_irq, - .irq_unmask = its_unmask_irq, - .irq_eoi = its_eoi_irq, - .irq_set_affinity = its_set_affinity, -}; - -/* * How we allocate LPIs: * * The GIC has id_bits bits for interrupt identifiers. From there, we @@ -640,7 +565,7 @@ static int its_lpi_to_chunk(int lpi) return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT; } -static int its_chunk_to_lpi(int chunk) +int its_chunk_to_lpi(int chunk) { return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192; } @@ -649,31 +574,29 @@ static int its_lpi_init(u32 id_bits) { lpi_chunks = its_lpi_to_chunk(1UL << id_bits); - lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long), - GFP_KERNEL); + lpi_bitmap = xzalloc_bytes(lpi_chunks / 8); if (!lpi_bitmap) { lpi_chunks = 0; return -ENOMEM; } - pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks); + its_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks); return 0; } -static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids) +static unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids) { unsigned long *bitmap = NULL; int chunk_id; int nr_chunks; int i; - nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK); + nr_chunks = DIV_ROUND_UP(nr_irq, IRQS_PER_CHUNK); spin_lock(&lpi_lock); do { - chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks, - 0, nr_chunks, 0); + chunk_id = find_next_zero_bit(lpi_bitmap, lpi_chunks, 0); if (chunk_id < lpi_chunks) break; @@ -683,8 +606,7 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids) if (!nr_chunks) goto out; - bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long), - GFP_ATOMIC); + bitmap = xzalloc_bytes(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long)); if (!bitmap) goto out; @@ -700,7 +622,7 @@ out: return bitmap; } -static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids) +void its_lpi_free(unsigned long *bitmap, int base, int nr_ids) { int lpi; @@ -712,13 +634,13 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids) if (test_bit(chunk, lpi_bitmap)) { clear_bit(chunk, lpi_bitmap); } else { - pr_err("Bad LPI chunk %d\n", chunk); + its_err("Bad LPI chunk %d\n", chunk); } } spin_unlock(&lpi_lock); - kfree(bitmap); + xfree(bitmap); } /* @@ -732,31 +654,28 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids) /* * This is how many bits of ID we need, including the useless ones. */ -#define LPI_NRBITS ilog2(LPI_PROPBASE_SZ + SZ_8K) +#define LPI_NRBITS (fls(LPI_PROPBASE_SZ + SZ_8K) - 1) -#define LPI_PROP_DEFAULT_PRIO 0xa0 +#define LPI_PROP_DEFAULT_PRIO 0xa2 static int __init its_alloc_lpi_tables(void) { - phys_addr_t paddr; + gic_rdists->prop_page = alloc_xenheap_pages(get_order_from_bytes(LPI_PROPBASE_SZ), 0); - gic_rdists->prop_page = alloc_pages(GFP_NOWAIT, - get_order(LPI_PROPBASE_SZ)); if (!gic_rdists->prop_page) { - pr_err("Failed to allocate PROPBASE\n"); + its_err("Failed to allocate PROPBASE\n"); return -ENOMEM; } - paddr = page_to_phys(gic_rdists->prop_page); - pr_info("GIC: using LPI property table @%pa\n", &paddr); + its_info("GIC: using LPI property table @%pa\n", gic_rdists->prop_page); /* Priority 0xa0, Group-1, disabled */ - memset(page_address(gic_rdists->prop_page), + memset(gic_rdists->prop_page, LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1, LPI_PROPBASE_SZ); /* Make sure the GIC will observe the written configuration */ - __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ); + clean_dcache_va_range(gic_rdists->prop_page, LPI_PROPBASE_SZ); return 0; } @@ -777,7 +696,7 @@ static void its_free_tables(struct its_node *its) for (i = 0; i < GITS_BASER_NR_REGS; i++) { if (its->tables[i]) { - free_page((unsigned long)its->tables[i]); + xfree(its->tables[i]); its->tables[i] = NULL; } } @@ -806,17 +725,18 @@ static int its_alloc_tables(struct its_node *its) if (type == GITS_BASER_TYPE_NONE) continue; - base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(max_ittsize)); + base = alloc_xenheap_pages(get_order_from_bytes(max_ittsize), 0); if (!base) { err = -ENOMEM; goto out_free; } - + memset(base, 0, max_ittsize); + clear_page(base); its->tables[i] = base; retry_baser: - val = (virt_to_phys(base) | + val = (__pa(base) | (type << GITS_BASER_TYPE_SHIFT) | ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) | GITS_BASER_WaWb | @@ -874,17 +794,16 @@ retry_baser: tmp = tmp << 5; if (val != tmp) { - pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n", - its->msi_chip.of_node->full_name, i, - (unsigned long) val, (unsigned long) tmp); + its_err("ITS: GITS_BASER%d doesn't stick: %lx %lx\n", + i, (unsigned long) val, (unsigned long) tmp); err = -ENXIO; goto out_free; } - pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", + its_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n", (int)(PAGE_SIZE / entry_size), its_base_type_string[type], - (unsigned long)virt_to_phys(base), + (unsigned long)__pa(base), psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); } @@ -898,8 +817,7 @@ out_free: static int its_alloc_collections(struct its_node *its) { - its->collections = kzalloc(nr_cpu_ids * sizeof(*its->collections), - GFP_KERNEL); + its->collections = xzalloc_array(struct its_collection, nr_cpu_ids); if (!its->collections) return -ENOMEM; @@ -909,32 +827,30 @@ static int its_alloc_collections(struct its_node *its) static void its_cpu_init_lpis(void) { void __iomem *rbase = gic_data_rdist_rd_base(); - struct page *pend_page; + void *pend_page; u64 val, tmp; /* If we didn't allocate the pending table yet, do it now */ - pend_page = gic_data_rdist()->pend_page; + pend_page = gic_data_rdist().pend_page; if (!pend_page) { - phys_addr_t paddr; /* * The pending pages have to be at least 64kB aligned, * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below. */ - pend_page = alloc_pages(GFP_NOWAIT | __GFP_ZERO, - get_order(max(LPI_PENDBASE_SZ, SZ_64K))); + pend_page = alloc_xenheap_pages(get_order_from_bytes(max(LPI_PENDBASE_SZ, SZ_64K)), 0); if (!pend_page) { - pr_err("Failed to allocate PENDBASE for CPU%d\n", + its_err("Failed to allocate PENDBASE for CPU%d\n", smp_processor_id()); return; } + memset(pend_page, 0, max(LPI_PENDBASE_SZ, SZ_64K)); /* Make sure the GIC will observe the zero-ed page */ - __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ); + clean_dcache_va_range(pend_page, LPI_PENDBASE_SZ); - paddr = page_to_phys(pend_page); - pr_info("CPU%d: using LPI pending table @%pa\n", - smp_processor_id(), &paddr); - gic_data_rdist()->pend_page = pend_page; + its_info("CPU%d: using LPI pending table @%pa\n", + smp_processor_id(), pend_page); + gic_data_rdist().pend_page = pend_page; } /* Disable LPIs */ @@ -948,7 +864,7 @@ static void its_cpu_init_lpis(void) dsb(sy); /* set PROPBASE */ - val = (page_to_phys(gic_rdists->prop_page) | + val = (__pa(gic_rdists->prop_page) | GICR_PROPBASER_InnerShareable | GICR_PROPBASER_WaWb | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); @@ -957,12 +873,12 @@ static void its_cpu_init_lpis(void) tmp = readq_relaxed(rbase + GICR_PROPBASER); if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { - pr_info_once("GIC: using cache flushing for LPI property table\n"); + its_info("GIC: using cache flushing for LPI property table\n"); gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING; } /* set PENDBASE */ - val = (page_to_phys(pend_page) | + val = (__pa(pend_page) | GICR_PROPBASER_InnerShareable | GICR_PROPBASER_WaWb); @@ -997,7 +913,7 @@ static void its_cpu_init_collection(void) * This ITS wants the physical address of the * redistributor. */ - target = gic_data_rdist()->phys_base; + target = gic_data_rdist().phys_base; } else { /* * This ITS wants a linear CPU number. @@ -1017,11 +933,11 @@ static void its_cpu_init_collection(void) spin_unlock(&its_lock); } -static struct its_device *its_find_device(struct its_node *its, u32 dev_id) +struct its_device *its_find_device(struct its_node *its, u32 dev_id) { struct its_device *its_dev = NULL, *tmp; - raw_spin_lock(&its->lock); + spin_lock(&its->lock); list_for_each_entry(tmp, &its->its_device_list, entry) { if (tmp->device_id == dev_id) { @@ -1030,13 +946,14 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id) } } - raw_spin_unlock(&its->lock); + spin_unlock(&its->lock); return its_dev; } -static struct its_device *its_create_device(struct its_node *its, u32 dev_id, - int nvecs) +/* TODO: Removed static for compilation */ +struct its_device *its_create_device(struct its_node *its, u32 dev_id, + int nvecs) { struct its_device *dev; unsigned long *lpi_map; @@ -1046,16 +963,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, int cpu; int sz; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = xzalloc(struct its_device); sz = nvecs * its->ite_size; sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; - itt = kmalloc(sz, GFP_KERNEL); + itt = xzalloc_bytes(sz); lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis); if (!dev || !itt || !lpi_map) { - kfree(dev); - kfree(itt); - kfree(lpi_map); + xfree(dev); + xfree(itt); + xfree(lpi_map); return NULL; } @@ -1068,12 +985,12 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, dev->device_id = dev_id; INIT_LIST_HEAD(&dev->entry); - raw_spin_lock(&its->lock); + spin_lock(&its->lock); list_add(&dev->entry, &its->its_device_list); - raw_spin_unlock(&its->lock); + spin_unlock(&its->lock); /* Bind the device to the first possible CPU */ - cpu = cpumask_first(cpu_online_mask); + cpu = cpumask_first(&cpu_online_map); dev->collection = &its->collections[cpu]; /* Map device to its ITT */ @@ -1082,17 +999,18 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, return dev; } -static void its_free_device(struct its_device *its_dev) +void its_free_device(struct its_device *its_dev) { - raw_spin_lock(&its_dev->its->lock); + spin_lock(&its_dev->its->lock); list_del(&its_dev->entry); - raw_spin_unlock(&its_dev->its->lock); - kfree(its_dev->itt); - kfree(its_dev); + spin_unlock(&its_dev->its->lock); + xfree(its_dev->itt); + xfree(its_dev); } -static int its_alloc_device_irq(struct its_device *dev, u32 id, - int *hwirq, unsigned int *irq) +/* TODO: Removed static for compilation */ +int its_alloc_device_irq(struct its_device *dev, u32 id, + int *hwirq, unsigned int *irq) { int idx; @@ -1101,9 +1019,6 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id, return -ENOSPC; *hwirq = dev->lpi_base + idx; - *irq = irq_create_mapping(lpi_domain, *hwirq); - if (!*irq) - return -ENOSPC; /* Don't kill the device, though */ set_bit(idx, dev->lpi_map); @@ -1113,134 +1028,52 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id, return 0; } - - -static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc *desc) -{ -#ifdef CONFIG_PCI_MSI - if (desc->msi_attrib.is_msix) - return pci_msix_vec_count(pdev); - else - return pci_msi_vec_count(pdev); -#else - return -EINVAL; -#endif -} - -int pci_requester_id(struct pci_dev *dev); -static int its_msi_setup_irq(struct msi_chip *chip, - struct pci_dev *pdev, - struct msi_desc *desc) -{ - struct its_node *its = container_of(chip, struct its_node, msi_chip); - struct its_device *its_dev; - struct msi_msg msg; - unsigned int irq; - u64 addr; - int hwirq; - int err; - u32 dev_id = pci_requester_id(pdev); - u32 vec_nr; - - its_dev = its_find_device(its, dev_id); - if (!its_dev) { - int nvec = its_msi_get_vec_count(pdev, desc); - if (WARN_ON(nvec <= 0)) - return nvec; - its_dev = its_create_device(its, dev_id, nvec); - } - if (!its_dev) - return -ENOMEM; - vec_nr = its_msi_get_entry_nr(desc); - err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq); - if (err) - return err; - - irq_set_msi_desc(irq, desc); - irq_set_handler_data(irq, its_dev); - - addr = its->phys_base + GITS_TRANSLATER; - - msg.address_lo = (u32)addr; - msg.address_hi = (u32)(addr >> 32); - msg.data = vec_nr; - - write_msi_msg(irq, &msg); - return 0; -} - -static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - struct its_device *its_dev = irq_data_get_irq_handler_data(d); - - BUG_ON(d->hwirq < its_dev->lpi_base || /* OMG! */ - d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis)); - - /* Stop the delivery of interrupts */ - its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc)); - - /* Mark interrupt index as unused, and clear the mapping */ - clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map); - irq_dispose_mapping(irq); - - /* If all interrupts have been freed, start mopping the floor */ - if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) { - its_lpi_free(its_dev->lpi_map, - its_dev->lpi_base, - its_dev->nr_lpis); - - /* Unmap device/itt */ - its_send_mapd(its_dev, 0); - its_free_device(its_dev); - } -} - -static int its_probe(struct device_node *node) +static int its_probe(struct dt_device_node *node) { - struct resource res; + paddr_t its_addr, its_size; struct its_node *its; void __iomem *its_base; u32 val; u64 baser, tmp; int err; - err = of_address_to_resource(node, 0, &res); - if (err) { - pr_warn("%s: no regs?\n", node->full_name); + err = dt_device_get_address(node, 0, &its_addr, &its_size); + if ( err || !its_addr ) + { + its_warn("%s: cannot find GIC-ITS\n", node->full_name); return -ENXIO; } - its_base = ioremap(res.start, resource_size(&res)); - if (!its_base) { - pr_warn("%s: unable to map registers\n", node->full_name); + its_base = ioremap_nocache(its_addr, its_size); + if ( !its_base) + { + its_warn("%s: unable to map registers\n", node->full_name); return -ENOMEM; } - val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK; + val = readl_relaxed(its_base + GITS_PIDR2) & GICR_PIDR2_ARCH_REV_MASK; if (val != 0x30 && val != 0x40) { - pr_warn("%s: no ITS detected, giving up\n", node->full_name); + its_warn("%s: no ITS detected, giving up\n", node->full_name); err = -ENODEV; goto out_unmap; } - pr_info("ITS: %s\n", node->full_name); + its_info("ITS: %s\n", node->full_name); - its = kzalloc(sizeof(*its), GFP_KERNEL); + its = xzalloc(struct its_node); if (!its) { err = -ENOMEM; goto out_unmap; } - raw_spin_lock_init(&its->lock); + spin_lock_init(&its->lock); INIT_LIST_HEAD(&its->entry); INIT_LIST_HEAD(&its->its_device_list); its->base = its_base; - its->phys_base = res.start; - its->msi_chip.of_node = node; + its->phys_base = its_addr; its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; - its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); + its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ); if (!its->cmd_base) { err = -ENOMEM; goto out_free_its; @@ -1255,19 +1088,19 @@ static int its_probe(struct device_node *node) if (err) goto out_free_tables; - baser = (virt_to_phys(its->cmd_base) | - GITS_CBASER_WaWb | - GITS_CBASER_InnerShareable | - (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | - GITS_CBASER_VALID); + baser = (__pa(its->cmd_base) | + GITS_CBASER_WaWb | + GITS_CBASER_InnerShareable | + (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | + GITS_CBASER_VALID); writeq_relaxed(baser, its->base + GITS_CBASER); tmp = readq_relaxed(its->base + GITS_CBASER); -/* writeq_relaxed(0, its->base + GITS_CWRITER); */ + writeq_relaxed(0, its->base + GITS_CWRITER); writel_relaxed(1, its->base + GITS_CTLR); if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) { - pr_info("ITS: using cache flushing for cmd queue\n"); + its_info("ITS: using cache flushing for cmd queue\n"); its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING; } @@ -1275,25 +1108,17 @@ static int its_probe(struct device_node *node) list_add(&its->entry, &its_nodes); spin_unlock(&its_lock); - if (IS_ENABLED(CONFIG_PCI_MSI) && /* Remove this once we have PCI... */ - of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { - its->msi_chip.setup_irq = its_msi_setup_irq; - its->msi_chip.teardown_irq = its_msi_teardown_irq; - - err = of_pci_msi_chip_add(&its->msi_chip); - } - return err; out_free_tables: its_free_tables(its); out_free_cmd: - kfree(its->cmd_base); + xfree(its->cmd_base); out_free_its: - kfree(its); + xfree(its); out_unmap: - iounmap(its_base); - pr_err("ITS: failed probing %s (%d)\n", node->full_name, err); + //TODO: no call for iounmap in xen? + its_err("ITS: failed probing %s (%d)\n", node->full_name, err); return err; } @@ -1305,7 +1130,7 @@ static bool gic_rdists_supports_plpis(void) int its_cpu_init(void) { if (!gic_rdists_supports_plpis()) { - pr_info("CPU%d: LPIs not supported\n", smp_processor_id()); + its_info("CPU%d: LPIs not supported\n", smp_processor_id()); return -ENXIO; } @@ -1317,32 +1142,45 @@ int its_cpu_init(void) return 0; } -static struct of_device_id its_device_id[] = { - { .compatible = "arm,gic-v3-its", }, - {}, -}; - -struct irq_chip *its_init(struct device_node *node, struct rdists *rdists, - struct irq_domain *domain) +int its_init(struct dt_device_node *node, struct rdist_prop *rdists) { - struct device_node *np; + static const struct dt_device_match its_device_ids[] __initconst = + { + DT_MATCH_COMPATIBLE("arm,gic-v3-its"), + { /* sentinel */ }, + }; + struct dt_device_node *np = NULL; - for (np = of_find_matching_node(node, its_device_id); np; - np = of_find_matching_node(np, its_device_id)) { - its_probe(np); + while ( (np = dt_find_matching_node(np, its_device_ids)) ) + { + if ( !dt_find_property(np, "msi-controller", NULL) ) + continue; + + if ( dt_get_parent(np) ) + break; } + if ( np ) + its_probe(np); if (list_empty(&its_nodes)) { - pr_info("ITS: No ITS available, not enabling LPIs\n"); - return NULL; + its_info("ITS: No ITS available, not enabling LPIs\n"); + return -ENXIO; } gic_rdists = rdists; gic_root_node = node; - lpi_domain = domain; its_alloc_lpi_tables(); its_lpi_init(rdists->id_bits); - return &its_irq_chip; + return 0; } + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 47452ca..5c35ac5 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -63,6 +63,7 @@ static struct gic_info gicv3_info; /* per-cpu re-distributor base */ static DEFINE_PER_CPU(void __iomem*, rbase); +DEFINE_PER_CPU(struct rdist, rdist); #define GICD (gicv3.map_dbase) #define GICD_RDIST_BASE (this_cpu(rbase)) diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h index 13adb53..83d75cf 100644 --- a/xen/include/asm-arm/gic_v3_defs.h +++ b/xen/include/asm-arm/gic_v3_defs.h @@ -110,6 +110,23 @@ #define GICR_ICFGR1 (0x0C04) #define GICR_NSACR (0x0E00) +#define GICR_CTLR_ENABLE_LPIS (1UL << 0) +#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) + +#define GICR_PROPBASER_NonShareable (0U << 10) +#define GICR_PROPBASER_InnerShareable (1U << 10) +#define GICR_PROPBASER_OuterShareable (2U << 10) +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10) +#define GICR_PROPBASER_nCnB (0U << 7) +#define GICR_PROPBASER_nC (1U << 7) +#define GICR_PROPBASER_RaWt (2U << 7) +#define GICR_PROPBASER_RaWb (3U << 7) +#define GICR_PROPBASER_WaWt (4U << 7) +#define GICR_PROPBASER_WaWb (5U << 7) +#define GICR_PROPBASER_RaWaWt (6U << 7) +#define GICR_PROPBASER_RaWaWb (7U << 7) +#define GICR_PROPBASER_IDBITS_MASK (0x1f) + #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) #define GICR_TYPER_LAST (1U << 4) @@ -149,6 +166,116 @@ #define ICH_SGI_IRQ_SHIFT 24 #define ICH_SGI_IRQ_MASK 0xf #define ICH_SGI_TARGETLIST_MASK 0xffff + +#define GICR_TYPER_PLPIS (1U << 0) +#define GICR_TYPER_VLPIS (1U << 1) +#define GICR_TYPER_LAST (1U << 4) + +#define LPI_PROP_GROUP1 (1 << 1) +#define LPI_PROP_ENABLED (1 << 0) + +/* + * ITS registers, offsets from ITS_base + */ +#define GITS_CTLR 0x0000 +#define GITS_IIDR 0x0004 +#define GITS_TYPER 0x0008 +#define GITS_CBASER 0x0080 +#define GITS_CWRITER 0x0088 +#define GITS_CREADR 0x0090 +#define GITS_BASER 0x0100 +#define GITS_BASERN 0x013c +#define GITS_PIDR0 GICR_PIDR0 +#define GITS_PIDR1 GICR_PIDR1 +#define GITS_PIDR2 GICR_PIDR2 +#define GITS_PIDR3 GICR_PIDR3 +#define GITS_PIDR4 GICR_PIDR4 +#define GITS_PIDR5 GICR_PIDR5 +#define GITS_PIDR7 GICR_PIDR7 + +#define GITS_TRANSLATER 0x10040 + +#define GITS_TYPER_PTA (1UL << 19) + +#define GITS_CBASER_VALID (1UL << 63) +#define GITS_CBASER_nCnB (0UL << 59) +#define GITS_CBASER_nC (1UL << 59) +#define GITS_CBASER_RaWt (2UL << 59) +#define GITS_CBASER_RaWb (3UL << 59) +#define GITS_CBASER_WaWt (4UL << 59) +#define GITS_CBASER_WaWb (5UL << 59) +#define GITS_CBASER_RaWaWt (6UL << 59) +#define GITS_CBASER_RaWaWb (7UL << 59) +#define GITS_CBASER_NonShareable (0UL << 10) +#define GITS_CBASER_InnerShareable (1UL << 10) +#define GITS_CBASER_OuterShareable (2UL << 10) +#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10) + +#define GITS_BASER_NR_REGS 8 + +#define GITS_BASER_VALID (1UL << 63) +#define GITS_BASER_nCnB (0UL << 59) +#define GITS_BASER_nC (1UL << 59) +#define GITS_BASER_RaWt (2UL << 59) +#define GITS_BASER_RaWb (3UL << 59) +#define GITS_BASER_WaWt (4UL << 59) +#define GITS_BASER_WaWb (5UL << 59) +#define GITS_BASER_RaWaWt (6UL << 59) +#define GITS_BASER_RaWaWb (7UL << 59) +#define GITS_BASER_TYPE_SHIFT (56) +#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) +#define GITS_BASER_ENTRY_SIZE_SHIFT (48) +#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1) +#define GITS_BASER_NonShareable (0UL << 10) +#define GITS_BASER_InnerShareable (1UL << 10) +#define GITS_BASER_OuterShareable (2UL << 10) +#define GITS_BASER_SHAREABILITY_SHIFT (10) +#define GITS_BASER_SHAREABILITY_MASK (3UL << GITS_BASER_SHAREABILITY_SHIFT) +#define GITS_BASER_PAGE_SIZE_SHIFT (8) +#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) + +#define GITS_BASER_TYPE_NONE 0 +#define GITS_BASER_TYPE_DEVICE 1 +#define GITS_BASER_TYPE_VCPU 2 +#define GITS_BASER_TYPE_CPU 3 +#define GITS_BASER_TYPE_COLLECTION 4 +#define GITS_BASER_TYPE_RESERVED5 5 +#define GITS_BASER_TYPE_RESERVED6 6 +#define GITS_BASER_TYPE_RESERVED7 7 + +/* + * ITS commands + */ +#define GITS_CMD_MAPD 0x08 +#define GITS_CMD_MAPC 0x09 +#define GITS_CMD_MAPVI 0x0a +#define GITS_CMD_MAPI 0x0b +#define GITS_CMD_MOVI 0x01 +#define GITS_CMD_DISCARD 0x0f +#define GITS_CMD_INV 0x0c +#define GITS_CMD_MOVALL 0x0e +#define GITS_CMD_INVALL 0x0d +#define GITS_CMD_INT 0x03 +#define GITS_CMD_CLEAR 0x04 +#define GITS_CMD_SYNC 0x05 + +struct rdist { + void __iomem *rbase; + void * pend_page; + paddr_t phys_base; +}; + +struct rdist_prop { + void * prop_page; + int id_bits; + uint64_t flags; +}; + +DECLARE_PER_CPU(struct rdist, rdist); + #endif /* __ASM_ARM_GIC_V3_DEFS_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 |