Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch irq/qcom-pdc-cleanup into irq/irqchip-next

* irq/qcom-pdc-cleanup:
: .
: Spring cleanup for the Qualcomm PDC driver, simplifying its
: use of irq domains, replacing open-coded functionnalities with
: the core code equivalent, and fixing the dodgy locking.
: .
irqchip/qcom-pdc: Drop open coded version of __assign_bit()
irqchip/qcom-pdc: Fix broken locking
irqchip/qcom-pdc: Kill qcom_pdc_translate helper
irqchip/qcom-pdc: Kill non-wakeup irqdomain
irqchip/qcom-pdc: Kill PDC_NO_PARENT_IRQ

Signed-off-by: Marc Zyngier <maz@kernel.org>

+29 -110
+29 -110
drivers/irqchip/qcom-pdc.c
··· 21 21 #include <linux/slab.h> 22 22 #include <linux/types.h> 23 23 24 - #define PDC_MAX_IRQS 168 25 24 #define PDC_MAX_GPIO_IRQS 256 26 - 27 - #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) 28 - #define ENABLE_INTR(reg, intr) (reg | (1 << intr)) 29 25 30 26 #define IRQ_ENABLE_BANK 0x10 31 27 #define IRQ_i_CFG 0x110 32 - 33 - #define PDC_NO_PARENT_IRQ ~0UL 34 28 35 29 struct pdc_pin_region { 36 30 u32 pin_base; 37 31 u32 parent_base; 38 32 u32 cnt; 39 33 }; 34 + 35 + #define pin_to_hwirq(r, p) ((r)->parent_base + (p) - (r)->pin_base) 40 36 41 37 static DEFINE_RAW_SPINLOCK(pdc_lock); 42 38 static void __iomem *pdc_base; ··· 52 56 static void pdc_enable_intr(struct irq_data *d, bool on) 53 57 { 54 58 int pin_out = d->hwirq; 59 + unsigned long enable; 60 + unsigned long flags; 55 61 u32 index, mask; 56 - u32 enable; 57 62 58 63 index = pin_out / 32; 59 64 mask = pin_out % 32; 60 65 61 - raw_spin_lock(&pdc_lock); 66 + raw_spin_lock_irqsave(&pdc_lock, flags); 62 67 enable = pdc_reg_read(IRQ_ENABLE_BANK, index); 63 - enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); 68 + __assign_bit(mask, &enable, on); 64 69 pdc_reg_write(IRQ_ENABLE_BANK, index, enable); 65 - raw_spin_unlock(&pdc_lock); 70 + raw_spin_unlock_irqrestore(&pdc_lock, flags); 66 71 } 67 72 68 73 static void qcom_pdc_gic_disable(struct irq_data *d) ··· 183 186 .irq_set_affinity = irq_chip_set_affinity_parent, 184 187 }; 185 188 186 - static irq_hw_number_t get_parent_hwirq(int pin) 189 + static struct pdc_pin_region *get_pin_region(int pin) 187 190 { 188 191 int i; 189 - struct pdc_pin_region *region; 190 192 191 193 for (i = 0; i < pdc_region_cnt; i++) { 192 - region = &pdc_region[i]; 193 - if (pin >= region->pin_base && 194 - pin < region->pin_base + region->cnt) 195 - return (region->parent_base + pin - region->pin_base); 194 + if (pin >= pdc_region[i].pin_base && 195 + pin < pdc_region[i].pin_base + pdc_region[i].cnt) 196 + return &pdc_region[i]; 196 197 } 197 198 198 - return PDC_NO_PARENT_IRQ; 199 - } 200 - 201 - static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec, 202 - unsigned long *hwirq, unsigned int *type) 203 - { 204 - if (is_of_node(fwspec->fwnode)) { 205 - if (fwspec->param_count != 2) 206 - return -EINVAL; 207 - 208 - *hwirq = fwspec->param[0]; 209 - *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; 210 - return 0; 211 - } 212 - 213 - return -EINVAL; 199 + return NULL; 214 200 } 215 201 216 202 static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, ··· 201 221 { 202 222 struct irq_fwspec *fwspec = data; 203 223 struct irq_fwspec parent_fwspec; 204 - irq_hw_number_t hwirq, parent_hwirq; 224 + struct pdc_pin_region *region; 225 + irq_hw_number_t hwirq; 205 226 unsigned int type; 206 227 int ret; 207 228 208 - ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type); 209 - if (ret) 210 - return ret; 211 - 212 - ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, 213 - &qcom_pdc_gic_chip, NULL); 214 - if (ret) 215 - return ret; 216 - 217 - parent_hwirq = get_parent_hwirq(hwirq); 218 - if (parent_hwirq == PDC_NO_PARENT_IRQ) 219 - return irq_domain_disconnect_hierarchy(domain->parent, virq); 220 - 221 - if (type & IRQ_TYPE_EDGE_BOTH) 222 - type = IRQ_TYPE_EDGE_RISING; 223 - 224 - if (type & IRQ_TYPE_LEVEL_MASK) 225 - type = IRQ_TYPE_LEVEL_HIGH; 226 - 227 - parent_fwspec.fwnode = domain->parent->fwnode; 228 - parent_fwspec.param_count = 3; 229 - parent_fwspec.param[0] = 0; 230 - parent_fwspec.param[1] = parent_hwirq; 231 - parent_fwspec.param[2] = type; 232 - 233 - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 234 - &parent_fwspec); 235 - } 236 - 237 - static const struct irq_domain_ops qcom_pdc_ops = { 238 - .translate = qcom_pdc_translate, 239 - .alloc = qcom_pdc_alloc, 240 - .free = irq_domain_free_irqs_common, 241 - }; 242 - 243 - static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, 244 - unsigned int nr_irqs, void *data) 245 - { 246 - struct irq_fwspec *fwspec = data; 247 - struct irq_fwspec parent_fwspec; 248 - irq_hw_number_t hwirq, parent_hwirq; 249 - unsigned int type; 250 - int ret; 251 - 252 - ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type); 229 + ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); 253 230 if (ret) 254 231 return ret; 255 232 ··· 218 281 if (ret) 219 282 return ret; 220 283 221 - parent_hwirq = get_parent_hwirq(hwirq); 222 - if (parent_hwirq == PDC_NO_PARENT_IRQ) 284 + region = get_pin_region(hwirq); 285 + if (!region) 223 286 return irq_domain_disconnect_hierarchy(domain->parent, virq); 224 287 225 288 if (type & IRQ_TYPE_EDGE_BOTH) ··· 231 294 parent_fwspec.fwnode = domain->parent->fwnode; 232 295 parent_fwspec.param_count = 3; 233 296 parent_fwspec.param[0] = 0; 234 - parent_fwspec.param[1] = parent_hwirq; 297 + parent_fwspec.param[1] = pin_to_hwirq(region, hwirq); 235 298 parent_fwspec.param[2] = type; 236 299 237 300 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, 238 301 &parent_fwspec); 239 302 } 240 303 241 - static int qcom_pdc_gpio_domain_select(struct irq_domain *d, 242 - struct irq_fwspec *fwspec, 243 - enum irq_domain_bus_token bus_token) 244 - { 245 - return bus_token == DOMAIN_BUS_WAKEUP; 246 - } 247 - 248 - static const struct irq_domain_ops qcom_pdc_gpio_ops = { 249 - .select = qcom_pdc_gpio_domain_select, 250 - .alloc = qcom_pdc_gpio_alloc, 304 + static const struct irq_domain_ops qcom_pdc_ops = { 305 + .translate = irq_domain_translate_twocell, 306 + .alloc = qcom_pdc_alloc, 251 307 .free = irq_domain_free_irqs_common, 252 308 }; 253 309 ··· 291 361 292 362 static int qcom_pdc_init(struct device_node *node, struct device_node *parent) 293 363 { 294 - struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; 364 + struct irq_domain *parent_domain, *pdc_domain; 295 365 int ret; 296 366 297 367 pdc_base = of_iomap(node, 0); ··· 313 383 goto fail; 314 384 } 315 385 316 - pdc_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_IRQS, 317 - of_fwnode_handle(node), 318 - &qcom_pdc_ops, NULL); 386 + pdc_domain = irq_domain_create_hierarchy(parent_domain, 387 + IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP, 388 + PDC_MAX_GPIO_IRQS, 389 + of_fwnode_handle(node), 390 + &qcom_pdc_ops, NULL); 319 391 if (!pdc_domain) { 320 - pr_err("%pOF: GIC domain add failed\n", node); 392 + pr_err("%pOF: PDC domain add failed\n", node); 321 393 ret = -ENOMEM; 322 394 goto fail; 323 395 } 324 396 325 - pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain, 326 - IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP, 327 - PDC_MAX_GPIO_IRQS, 328 - of_fwnode_handle(node), 329 - &qcom_pdc_gpio_ops, NULL); 330 - if (!pdc_gpio_domain) { 331 - pr_err("%pOF: PDC domain add failed for GPIO domain\n", node); 332 - ret = -ENOMEM; 333 - goto remove; 334 - } 335 - 336 - irq_domain_update_bus_token(pdc_gpio_domain, DOMAIN_BUS_WAKEUP); 397 + irq_domain_update_bus_token(pdc_domain, DOMAIN_BUS_WAKEUP); 337 398 338 399 return 0; 339 400 340 - remove: 341 - irq_domain_remove(pdc_domain); 342 401 fail: 343 402 kfree(pdc_region); 344 403 iounmap(pdc_base);