0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) "genirq/ipi: " fmt
0010
0011 #include <linux/irqdomain.h>
0012 #include <linux/irq.h>
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 int irq_reserve_ipi(struct irq_domain *domain,
0024 const struct cpumask *dest)
0025 {
0026 unsigned int nr_irqs, offset;
0027 struct irq_data *data;
0028 int virq, i;
0029
0030 if (!domain ||!irq_domain_is_ipi(domain)) {
0031 pr_warn("Reservation on a non IPI domain\n");
0032 return -EINVAL;
0033 }
0034
0035 if (!cpumask_subset(dest, cpu_possible_mask)) {
0036 pr_warn("Reservation is not in possible_cpu_mask\n");
0037 return -EINVAL;
0038 }
0039
0040 nr_irqs = cpumask_weight(dest);
0041 if (!nr_irqs) {
0042 pr_warn("Reservation for empty destination mask\n");
0043 return -EINVAL;
0044 }
0045
0046 if (irq_domain_is_ipi_single(domain)) {
0047
0048
0049
0050
0051
0052
0053 nr_irqs = 1;
0054 offset = 0;
0055 } else {
0056 unsigned int next;
0057
0058
0059
0060
0061
0062
0063
0064 offset = cpumask_first(dest);
0065
0066
0067
0068
0069 next = cpumask_next_zero(offset, dest);
0070 if (next < nr_cpu_ids)
0071 next = cpumask_next(next, dest);
0072 if (next < nr_cpu_ids) {
0073 pr_warn("Destination mask has holes\n");
0074 return -EINVAL;
0075 }
0076 }
0077
0078 virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE, NULL);
0079 if (virq <= 0) {
0080 pr_warn("Can't reserve IPI, failed to alloc descs\n");
0081 return -ENOMEM;
0082 }
0083
0084 virq = __irq_domain_alloc_irqs(domain, virq, nr_irqs, NUMA_NO_NODE,
0085 (void *) dest, true, NULL);
0086
0087 if (virq <= 0) {
0088 pr_warn("Can't reserve IPI, failed to alloc hw irqs\n");
0089 goto free_descs;
0090 }
0091
0092 for (i = 0; i < nr_irqs; i++) {
0093 data = irq_get_irq_data(virq + i);
0094 cpumask_copy(data->common->affinity, dest);
0095 data->common->ipi_offset = offset;
0096 irq_set_status_flags(virq + i, IRQ_NO_BALANCING);
0097 }
0098 return virq;
0099
0100 free_descs:
0101 irq_free_descs(virq, nr_irqs);
0102 return -EBUSY;
0103 }
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest)
0116 {
0117 struct irq_data *data = irq_get_irq_data(irq);
0118 const struct cpumask *ipimask;
0119 struct irq_domain *domain;
0120 unsigned int nr_irqs;
0121
0122 if (!irq || !data)
0123 return -EINVAL;
0124
0125 domain = data->domain;
0126 if (WARN_ON(domain == NULL))
0127 return -EINVAL;
0128
0129 if (!irq_domain_is_ipi(domain)) {
0130 pr_warn("Trying to destroy a non IPI domain!\n");
0131 return -EINVAL;
0132 }
0133
0134 ipimask = irq_data_get_affinity_mask(data);
0135 if (!ipimask || WARN_ON(!cpumask_subset(dest, ipimask)))
0136
0137
0138
0139
0140 return -EINVAL;
0141
0142 if (irq_domain_is_ipi_per_cpu(domain)) {
0143 irq = irq + cpumask_first(dest) - data->common->ipi_offset;
0144 nr_irqs = cpumask_weight(dest);
0145 } else {
0146 nr_irqs = 1;
0147 }
0148
0149 irq_domain_free_irqs(irq, nr_irqs);
0150 return 0;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163 irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu)
0164 {
0165 struct irq_data *data = irq_get_irq_data(irq);
0166 const struct cpumask *ipimask;
0167
0168 if (!data || cpu >= nr_cpu_ids)
0169 return INVALID_HWIRQ;
0170
0171 ipimask = irq_data_get_affinity_mask(data);
0172 if (!ipimask || !cpumask_test_cpu(cpu, ipimask))
0173 return INVALID_HWIRQ;
0174
0175
0176
0177
0178
0179
0180
0181 if (irq_domain_is_ipi_per_cpu(data->domain))
0182 data = irq_get_irq_data(irq + cpu - data->common->ipi_offset);
0183
0184 return data ? irqd_to_hwirq(data) : INVALID_HWIRQ;
0185 }
0186 EXPORT_SYMBOL_GPL(ipi_get_hwirq);
0187
0188 static int ipi_send_verify(struct irq_chip *chip, struct irq_data *data,
0189 const struct cpumask *dest, unsigned int cpu)
0190 {
0191 const struct cpumask *ipimask = irq_data_get_affinity_mask(data);
0192
0193 if (!chip || !ipimask)
0194 return -EINVAL;
0195
0196 if (!chip->ipi_send_single && !chip->ipi_send_mask)
0197 return -EINVAL;
0198
0199 if (cpu >= nr_cpu_ids)
0200 return -EINVAL;
0201
0202 if (dest) {
0203 if (!cpumask_subset(dest, ipimask))
0204 return -EINVAL;
0205 } else {
0206 if (!cpumask_test_cpu(cpu, ipimask))
0207 return -EINVAL;
0208 }
0209 return 0;
0210 }
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 int __ipi_send_single(struct irq_desc *desc, unsigned int cpu)
0224 {
0225 struct irq_data *data = irq_desc_get_irq_data(desc);
0226 struct irq_chip *chip = irq_data_get_irq_chip(data);
0227
0228 #ifdef DEBUG
0229
0230
0231
0232
0233
0234 if (WARN_ON_ONCE(ipi_send_verify(chip, data, NULL, cpu)))
0235 return -EINVAL;
0236 #endif
0237 if (!chip->ipi_send_single) {
0238 chip->ipi_send_mask(data, cpumask_of(cpu));
0239 return 0;
0240 }
0241
0242
0243 if (irq_domain_is_ipi_per_cpu(data->domain) &&
0244 cpu != data->common->ipi_offset) {
0245
0246 unsigned irq = data->irq + cpu - data->common->ipi_offset;
0247
0248 data = irq_get_irq_data(irq);
0249 }
0250 chip->ipi_send_single(data, cpu);
0251 return 0;
0252 }
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest)
0266 {
0267 struct irq_data *data = irq_desc_get_irq_data(desc);
0268 struct irq_chip *chip = irq_data_get_irq_chip(data);
0269 unsigned int cpu;
0270
0271 #ifdef DEBUG
0272
0273
0274
0275
0276
0277 if (WARN_ON_ONCE(ipi_send_verify(chip, data, dest, 0)))
0278 return -EINVAL;
0279 #endif
0280 if (chip->ipi_send_mask) {
0281 chip->ipi_send_mask(data, dest);
0282 return 0;
0283 }
0284
0285 if (irq_domain_is_ipi_per_cpu(data->domain)) {
0286 unsigned int base = data->irq;
0287
0288 for_each_cpu(cpu, dest) {
0289 unsigned irq = base + cpu - data->common->ipi_offset;
0290
0291 data = irq_get_irq_data(irq);
0292 chip->ipi_send_single(data, cpu);
0293 }
0294 } else {
0295 for_each_cpu(cpu, dest)
0296 chip->ipi_send_single(data, cpu);
0297 }
0298 return 0;
0299 }
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 int ipi_send_single(unsigned int virq, unsigned int cpu)
0310 {
0311 struct irq_desc *desc = irq_to_desc(virq);
0312 struct irq_data *data = desc ? irq_desc_get_irq_data(desc) : NULL;
0313 struct irq_chip *chip = data ? irq_data_get_irq_chip(data) : NULL;
0314
0315 if (WARN_ON_ONCE(ipi_send_verify(chip, data, NULL, cpu)))
0316 return -EINVAL;
0317
0318 return __ipi_send_single(desc, cpu);
0319 }
0320 EXPORT_SYMBOL_GPL(ipi_send_single);
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330 int ipi_send_mask(unsigned int virq, const struct cpumask *dest)
0331 {
0332 struct irq_desc *desc = irq_to_desc(virq);
0333 struct irq_data *data = desc ? irq_desc_get_irq_data(desc) : NULL;
0334 struct irq_chip *chip = data ? irq_data_get_irq_chip(data) : NULL;
0335
0336 if (WARN_ON_ONCE(ipi_send_verify(chip, data, dest, 0)))
0337 return -EINVAL;
0338
0339 return __ipi_send_mask(desc, dest);
0340 }
0341 EXPORT_SYMBOL_GPL(ipi_send_mask);