0001
0002
0003
0004
0005
0006
0007 #include <linux/bitops.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/irqchip.h>
0010 #include <linux/irqchip/chained_irq.h>
0011 #include <linux/irqchip/irq-partition-percpu.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/seq_file.h>
0014 #include <linux/slab.h>
0015
0016 struct partition_desc {
0017 int nr_parts;
0018 struct partition_affinity *parts;
0019 struct irq_domain *domain;
0020 struct irq_desc *chained_desc;
0021 unsigned long *bitmap;
0022 struct irq_domain_ops ops;
0023 };
0024
0025 static bool partition_check_cpu(struct partition_desc *part,
0026 unsigned int cpu, unsigned int hwirq)
0027 {
0028 return cpumask_test_cpu(cpu, &part->parts[hwirq].mask);
0029 }
0030
0031 static void partition_irq_mask(struct irq_data *d)
0032 {
0033 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0034 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0035 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0036
0037 if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
0038 chip->irq_mask)
0039 chip->irq_mask(data);
0040 }
0041
0042 static void partition_irq_unmask(struct irq_data *d)
0043 {
0044 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0045 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0046 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0047
0048 if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
0049 chip->irq_unmask)
0050 chip->irq_unmask(data);
0051 }
0052
0053 static int partition_irq_set_irqchip_state(struct irq_data *d,
0054 enum irqchip_irq_state which,
0055 bool val)
0056 {
0057 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0058 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0059 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0060
0061 if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
0062 chip->irq_set_irqchip_state)
0063 return chip->irq_set_irqchip_state(data, which, val);
0064
0065 return -EINVAL;
0066 }
0067
0068 static int partition_irq_get_irqchip_state(struct irq_data *d,
0069 enum irqchip_irq_state which,
0070 bool *val)
0071 {
0072 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0073 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0074 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0075
0076 if (partition_check_cpu(part, smp_processor_id(), d->hwirq) &&
0077 chip->irq_get_irqchip_state)
0078 return chip->irq_get_irqchip_state(data, which, val);
0079
0080 return -EINVAL;
0081 }
0082
0083 static int partition_irq_set_type(struct irq_data *d, unsigned int type)
0084 {
0085 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0086 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0087 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0088
0089 if (chip->irq_set_type)
0090 return chip->irq_set_type(data, type);
0091
0092 return -EINVAL;
0093 }
0094
0095 static void partition_irq_print_chip(struct irq_data *d, struct seq_file *p)
0096 {
0097 struct partition_desc *part = irq_data_get_irq_chip_data(d);
0098 struct irq_chip *chip = irq_desc_get_chip(part->chained_desc);
0099 struct irq_data *data = irq_desc_get_irq_data(part->chained_desc);
0100
0101 seq_printf(p, " %5s-%lu", chip->name, data->hwirq);
0102 }
0103
0104 static struct irq_chip partition_irq_chip = {
0105 .irq_mask = partition_irq_mask,
0106 .irq_unmask = partition_irq_unmask,
0107 .irq_set_type = partition_irq_set_type,
0108 .irq_get_irqchip_state = partition_irq_get_irqchip_state,
0109 .irq_set_irqchip_state = partition_irq_set_irqchip_state,
0110 .irq_print_chip = partition_irq_print_chip,
0111 };
0112
0113 static void partition_handle_irq(struct irq_desc *desc)
0114 {
0115 struct partition_desc *part = irq_desc_get_handler_data(desc);
0116 struct irq_chip *chip = irq_desc_get_chip(desc);
0117 int cpu = smp_processor_id();
0118 int hwirq;
0119
0120 chained_irq_enter(chip, desc);
0121
0122 for_each_set_bit(hwirq, part->bitmap, part->nr_parts) {
0123 if (partition_check_cpu(part, cpu, hwirq))
0124 break;
0125 }
0126
0127 if (unlikely(hwirq == part->nr_parts))
0128 handle_bad_irq(desc);
0129 else
0130 generic_handle_domain_irq(part->domain, hwirq);
0131
0132 chained_irq_exit(chip, desc);
0133 }
0134
0135 static int partition_domain_alloc(struct irq_domain *domain, unsigned int virq,
0136 unsigned int nr_irqs, void *arg)
0137 {
0138 int ret;
0139 irq_hw_number_t hwirq;
0140 unsigned int type;
0141 struct irq_fwspec *fwspec = arg;
0142 struct partition_desc *part;
0143
0144 BUG_ON(nr_irqs != 1);
0145 ret = domain->ops->translate(domain, fwspec, &hwirq, &type);
0146 if (ret)
0147 return ret;
0148
0149 part = domain->host_data;
0150
0151 set_bit(hwirq, part->bitmap);
0152 irq_set_chained_handler_and_data(irq_desc_get_irq(part->chained_desc),
0153 partition_handle_irq, part);
0154 irq_set_percpu_devid_partition(virq, &part->parts[hwirq].mask);
0155 irq_domain_set_info(domain, virq, hwirq, &partition_irq_chip, part,
0156 handle_percpu_devid_irq, NULL, NULL);
0157 irq_set_status_flags(virq, IRQ_NOAUTOEN);
0158
0159 return 0;
0160 }
0161
0162 static void partition_domain_free(struct irq_domain *domain, unsigned int virq,
0163 unsigned int nr_irqs)
0164 {
0165 struct irq_data *d;
0166
0167 BUG_ON(nr_irqs != 1);
0168
0169 d = irq_domain_get_irq_data(domain, virq);
0170 irq_set_handler(virq, NULL);
0171 irq_domain_reset_irq_data(d);
0172 }
0173
0174 int partition_translate_id(struct partition_desc *desc, void *partition_id)
0175 {
0176 struct partition_affinity *part = NULL;
0177 int i;
0178
0179 for (i = 0; i < desc->nr_parts; i++) {
0180 if (desc->parts[i].partition_id == partition_id) {
0181 part = &desc->parts[i];
0182 break;
0183 }
0184 }
0185
0186 if (WARN_ON(!part)) {
0187 pr_err("Failed to find partition\n");
0188 return -EINVAL;
0189 }
0190
0191 return i;
0192 }
0193
0194 struct partition_desc *partition_create_desc(struct fwnode_handle *fwnode,
0195 struct partition_affinity *parts,
0196 int nr_parts,
0197 int chained_irq,
0198 const struct irq_domain_ops *ops)
0199 {
0200 struct partition_desc *desc;
0201 struct irq_domain *d;
0202
0203 BUG_ON(!ops->select || !ops->translate);
0204
0205 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
0206 if (!desc)
0207 return NULL;
0208
0209 desc->ops = *ops;
0210 desc->ops.free = partition_domain_free;
0211 desc->ops.alloc = partition_domain_alloc;
0212
0213 d = irq_domain_create_linear(fwnode, nr_parts, &desc->ops, desc);
0214 if (!d)
0215 goto out;
0216 desc->domain = d;
0217
0218 desc->bitmap = bitmap_zalloc(nr_parts, GFP_KERNEL);
0219 if (WARN_ON(!desc->bitmap))
0220 goto out;
0221
0222 desc->chained_desc = irq_to_desc(chained_irq);
0223 desc->nr_parts = nr_parts;
0224 desc->parts = parts;
0225
0226 return desc;
0227 out:
0228 if (d)
0229 irq_domain_remove(d);
0230 kfree(desc);
0231
0232 return NULL;
0233 }
0234
0235 struct irq_domain *partition_get_domain(struct partition_desc *dsc)
0236 {
0237 if (dsc)
0238 return dsc->domain;
0239
0240 return NULL;
0241 }