diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2014-11-24 09:35:15 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-11-26 10:55:14 -0500 |
commit | 84a6a2e7fc18dae444c5c88cc6af8878552867a5 (patch) | |
tree | d62abf1f3e14340a777f662cf86f91c7cc89f932 /drivers/irqchip | |
parent | 1ac19ca6bf97392a3a631551bac223893d24d21f (diff) |
irqchip: GICv3: ITS: device allocation and configuration
The ITS has a notion of "device" that can write to it in order to
generate an interrupt.
Conversly, the driver maintains a per-ITS list of devices, together
with their configuration information, and uses this to configure
the HW.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1416839720-18400-9-git-send-email-marc.zyngier@arm.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-gic-v3-its.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 03f9831da7b1..d687fd43fbbb 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c | |||
@@ -981,3 +981,77 @@ static void its_cpu_init_collection(void) | |||
981 | 981 | ||
982 | spin_unlock(&its_lock); | 982 | spin_unlock(&its_lock); |
983 | } | 983 | } |
984 | |||
985 | static struct its_device *its_find_device(struct its_node *its, u32 dev_id) | ||
986 | { | ||
987 | struct its_device *its_dev = NULL, *tmp; | ||
988 | |||
989 | raw_spin_lock(&its->lock); | ||
990 | |||
991 | list_for_each_entry(tmp, &its->its_device_list, entry) { | ||
992 | if (tmp->device_id == dev_id) { | ||
993 | its_dev = tmp; | ||
994 | break; | ||
995 | } | ||
996 | } | ||
997 | |||
998 | raw_spin_unlock(&its->lock); | ||
999 | |||
1000 | return its_dev; | ||
1001 | } | ||
1002 | |||
1003 | static struct its_device *its_create_device(struct its_node *its, u32 dev_id, | ||
1004 | int nvecs) | ||
1005 | { | ||
1006 | struct its_device *dev; | ||
1007 | unsigned long *lpi_map; | ||
1008 | void *itt; | ||
1009 | int lpi_base; | ||
1010 | int nr_lpis; | ||
1011 | int cpu; | ||
1012 | int sz; | ||
1013 | |||
1014 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
1015 | sz = nvecs * its->ite_size; | ||
1016 | sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; | ||
1017 | itt = kmalloc(sz, GFP_KERNEL); | ||
1018 | lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis); | ||
1019 | |||
1020 | if (!dev || !itt || !lpi_map) { | ||
1021 | kfree(dev); | ||
1022 | kfree(itt); | ||
1023 | kfree(lpi_map); | ||
1024 | return NULL; | ||
1025 | } | ||
1026 | |||
1027 | dev->its = its; | ||
1028 | dev->itt = itt; | ||
1029 | dev->nr_ites = nvecs; | ||
1030 | dev->lpi_map = lpi_map; | ||
1031 | dev->lpi_base = lpi_base; | ||
1032 | dev->nr_lpis = nr_lpis; | ||
1033 | dev->device_id = dev_id; | ||
1034 | INIT_LIST_HEAD(&dev->entry); | ||
1035 | |||
1036 | raw_spin_lock(&its->lock); | ||
1037 | list_add(&dev->entry, &its->its_device_list); | ||
1038 | raw_spin_unlock(&its->lock); | ||
1039 | |||
1040 | /* Bind the device to the first possible CPU */ | ||
1041 | cpu = cpumask_first(cpu_online_mask); | ||
1042 | dev->collection = &its->collections[cpu]; | ||
1043 | |||
1044 | /* Map device to its ITT */ | ||
1045 | its_send_mapd(dev, 1); | ||
1046 | |||
1047 | return dev; | ||
1048 | } | ||
1049 | |||
1050 | static void its_free_device(struct its_device *its_dev) | ||
1051 | { | ||
1052 | raw_spin_lock(&its_dev->its->lock); | ||
1053 | list_del(&its_dev->entry); | ||
1054 | raw_spin_unlock(&its_dev->its->lock); | ||
1055 | kfree(its_dev->itt); | ||
1056 | kfree(its_dev); | ||
1057 | } | ||