diff options
Diffstat (limited to 'drivers/gpio/gpio-thunderx.c')
-rw-r--r-- | drivers/gpio/gpio-thunderx.c | 163 |
1 files changed, 56 insertions, 107 deletions
diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index 715371b5102a..ddad5c7ea617 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c | |||
@@ -53,7 +53,6 @@ struct thunderx_line { | |||
53 | struct thunderx_gpio { | 53 | struct thunderx_gpio { |
54 | struct gpio_chip chip; | 54 | struct gpio_chip chip; |
55 | u8 __iomem *register_base; | 55 | u8 __iomem *register_base; |
56 | struct irq_domain *irqd; | ||
57 | struct msix_entry *msix_entries; /* per line MSI-X */ | 56 | struct msix_entry *msix_entries; /* per line MSI-X */ |
58 | struct thunderx_line *line_entries; /* per line irq info */ | 57 | struct thunderx_line *line_entries; /* per line irq info */ |
59 | raw_spinlock_t lock; | 58 | raw_spinlock_t lock; |
@@ -283,54 +282,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip, | |||
283 | } | 282 | } |
284 | } | 283 | } |
285 | 284 | ||
286 | static void thunderx_gpio_irq_ack(struct irq_data *data) | 285 | static void thunderx_gpio_irq_ack(struct irq_data *d) |
287 | { | 286 | { |
288 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | 287 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
288 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); | ||
289 | 289 | ||
290 | writeq(GPIO_INTR_INTR, | 290 | writeq(GPIO_INTR_INTR, |
291 | txline->txgpio->register_base + intr_reg(txline->line)); | 291 | txgpio->register_base + intr_reg(irqd_to_hwirq(d))); |
292 | } | 292 | } |
293 | 293 | ||
294 | static void thunderx_gpio_irq_mask(struct irq_data *data) | 294 | static void thunderx_gpio_irq_mask(struct irq_data *d) |
295 | { | 295 | { |
296 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | 296 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
297 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); | ||
297 | 298 | ||
298 | writeq(GPIO_INTR_ENA_W1C, | 299 | writeq(GPIO_INTR_ENA_W1C, |
299 | txline->txgpio->register_base + intr_reg(txline->line)); | 300 | txgpio->register_base + intr_reg(irqd_to_hwirq(d))); |
300 | } | 301 | } |
301 | 302 | ||
302 | static void thunderx_gpio_irq_mask_ack(struct irq_data *data) | 303 | static void thunderx_gpio_irq_mask_ack(struct irq_data *d) |
303 | { | 304 | { |
304 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | 305 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
306 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); | ||
305 | 307 | ||
306 | writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR, | 308 | writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR, |
307 | txline->txgpio->register_base + intr_reg(txline->line)); | 309 | txgpio->register_base + intr_reg(irqd_to_hwirq(d))); |
308 | } | 310 | } |
309 | 311 | ||
310 | static void thunderx_gpio_irq_unmask(struct irq_data *data) | 312 | static void thunderx_gpio_irq_unmask(struct irq_data *d) |
311 | { | 313 | { |
312 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | 314 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
315 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); | ||
313 | 316 | ||
314 | writeq(GPIO_INTR_ENA_W1S, | 317 | writeq(GPIO_INTR_ENA_W1S, |
315 | txline->txgpio->register_base + intr_reg(txline->line)); | 318 | txgpio->register_base + intr_reg(irqd_to_hwirq(d))); |
316 | } | 319 | } |
317 | 320 | ||
318 | static int thunderx_gpio_irq_set_type(struct irq_data *data, | 321 | static int thunderx_gpio_irq_set_type(struct irq_data *d, |
319 | unsigned int flow_type) | 322 | unsigned int flow_type) |
320 | { | 323 | { |
321 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | 324 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
322 | struct thunderx_gpio *txgpio = txline->txgpio; | 325 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); |
326 | struct thunderx_line *txline = | ||
327 | &txgpio->line_entries[irqd_to_hwirq(d)]; | ||
323 | u64 bit_cfg; | 328 | u64 bit_cfg; |
324 | 329 | ||
325 | irqd_set_trigger_type(data, flow_type); | 330 | irqd_set_trigger_type(d, flow_type); |
326 | 331 | ||
327 | bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN; | 332 | bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN; |
328 | 333 | ||
329 | if (flow_type & IRQ_TYPE_EDGE_BOTH) { | 334 | if (flow_type & IRQ_TYPE_EDGE_BOTH) { |
330 | irq_set_handler_locked(data, handle_fasteoi_ack_irq); | 335 | irq_set_handler_locked(d, handle_fasteoi_ack_irq); |
331 | bit_cfg |= GPIO_BIT_CFG_INT_TYPE; | 336 | bit_cfg |= GPIO_BIT_CFG_INT_TYPE; |
332 | } else { | 337 | } else { |
333 | irq_set_handler_locked(data, handle_fasteoi_mask_irq); | 338 | irq_set_handler_locked(d, handle_fasteoi_mask_irq); |
334 | } | 339 | } |
335 | 340 | ||
336 | raw_spin_lock(&txgpio->lock); | 341 | raw_spin_lock(&txgpio->lock); |
@@ -359,33 +364,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data) | |||
359 | irq_chip_disable_parent(data); | 364 | irq_chip_disable_parent(data); |
360 | } | 365 | } |
361 | 366 | ||
362 | static int thunderx_gpio_irq_request_resources(struct irq_data *data) | ||
363 | { | ||
364 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | ||
365 | struct thunderx_gpio *txgpio = txline->txgpio; | ||
366 | int r; | ||
367 | |||
368 | r = gpiochip_lock_as_irq(&txgpio->chip, txline->line); | ||
369 | if (r) | ||
370 | return r; | ||
371 | |||
372 | r = irq_chip_request_resources_parent(data); | ||
373 | if (r) | ||
374 | gpiochip_unlock_as_irq(&txgpio->chip, txline->line); | ||
375 | |||
376 | return r; | ||
377 | } | ||
378 | |||
379 | static void thunderx_gpio_irq_release_resources(struct irq_data *data) | ||
380 | { | ||
381 | struct thunderx_line *txline = irq_data_get_irq_chip_data(data); | ||
382 | struct thunderx_gpio *txgpio = txline->txgpio; | ||
383 | |||
384 | irq_chip_release_resources_parent(data); | ||
385 | |||
386 | gpiochip_unlock_as_irq(&txgpio->chip, txline->line); | ||
387 | } | ||
388 | |||
389 | /* | 367 | /* |
390 | * Interrupts are chained from underlying MSI-X vectors. We have | 368 | * Interrupts are chained from underlying MSI-X vectors. We have |
391 | * these irq_chip functions to be able to handle level triggering | 369 | * these irq_chip functions to be able to handle level triggering |
@@ -402,48 +380,22 @@ static struct irq_chip thunderx_gpio_irq_chip = { | |||
402 | .irq_unmask = thunderx_gpio_irq_unmask, | 380 | .irq_unmask = thunderx_gpio_irq_unmask, |
403 | .irq_eoi = irq_chip_eoi_parent, | 381 | .irq_eoi = irq_chip_eoi_parent, |
404 | .irq_set_affinity = irq_chip_set_affinity_parent, | 382 | .irq_set_affinity = irq_chip_set_affinity_parent, |
405 | .irq_request_resources = thunderx_gpio_irq_request_resources, | ||
406 | .irq_release_resources = thunderx_gpio_irq_release_resources, | ||
407 | .irq_set_type = thunderx_gpio_irq_set_type, | 383 | .irq_set_type = thunderx_gpio_irq_set_type, |
408 | 384 | ||
409 | .flags = IRQCHIP_SET_TYPE_MASKED | 385 | .flags = IRQCHIP_SET_TYPE_MASKED |
410 | }; | 386 | }; |
411 | 387 | ||
412 | static int thunderx_gpio_irq_translate(struct irq_domain *d, | 388 | static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, |
413 | struct irq_fwspec *fwspec, | 389 | unsigned int child, |
414 | irq_hw_number_t *hwirq, | 390 | unsigned int child_type, |
415 | unsigned int *type) | 391 | unsigned int *parent, |
392 | unsigned int *parent_type) | ||
416 | { | 393 | { |
417 | struct thunderx_gpio *txgpio = d->host_data; | 394 | struct thunderx_gpio *txgpio = gpiochip_get_data(gc); |
418 | |||
419 | if (WARN_ON(fwspec->param_count < 2)) | ||
420 | return -EINVAL; | ||
421 | if (fwspec->param[0] >= txgpio->chip.ngpio) | ||
422 | return -EINVAL; | ||
423 | *hwirq = fwspec->param[0]; | ||
424 | *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq, | ||
429 | unsigned int nr_irqs, void *arg) | ||
430 | { | ||
431 | struct thunderx_line *txline = arg; | ||
432 | 395 | ||
433 | return irq_domain_set_hwirq_and_chip(d, virq, txline->line, | 396 | *parent = txgpio->base_msi + (2 * child); |
434 | &thunderx_gpio_irq_chip, txline); | 397 | *parent_type = IRQ_TYPE_LEVEL_HIGH; |
435 | } | 398 | return 0; |
436 | |||
437 | static const struct irq_domain_ops thunderx_gpio_irqd_ops = { | ||
438 | .alloc = thunderx_gpio_irq_alloc, | ||
439 | .translate = thunderx_gpio_irq_translate | ||
440 | }; | ||
441 | |||
442 | static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) | ||
443 | { | ||
444 | struct thunderx_gpio *txgpio = gpiochip_get_data(chip); | ||
445 | |||
446 | return irq_find_mapping(txgpio->irqd, offset); | ||
447 | } | 399 | } |
448 | 400 | ||
449 | static int thunderx_gpio_probe(struct pci_dev *pdev, | 401 | static int thunderx_gpio_probe(struct pci_dev *pdev, |
@@ -453,6 +405,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, | |||
453 | struct device *dev = &pdev->dev; | 405 | struct device *dev = &pdev->dev; |
454 | struct thunderx_gpio *txgpio; | 406 | struct thunderx_gpio *txgpio; |
455 | struct gpio_chip *chip; | 407 | struct gpio_chip *chip; |
408 | struct gpio_irq_chip *girq; | ||
456 | int ngpio, i; | 409 | int ngpio, i; |
457 | int err = 0; | 410 | int err = 0; |
458 | 411 | ||
@@ -497,8 +450,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, | |||
497 | } | 450 | } |
498 | 451 | ||
499 | txgpio->msix_entries = devm_kcalloc(dev, | 452 | txgpio->msix_entries = devm_kcalloc(dev, |
500 | ngpio, sizeof(struct msix_entry), | 453 | ngpio, sizeof(struct msix_entry), |
501 | GFP_KERNEL); | 454 | GFP_KERNEL); |
502 | if (!txgpio->msix_entries) { | 455 | if (!txgpio->msix_entries) { |
503 | err = -ENOMEM; | 456 | err = -ENOMEM; |
504 | goto out; | 457 | goto out; |
@@ -539,27 +492,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, | |||
539 | if (err < 0) | 492 | if (err < 0) |
540 | goto out; | 493 | goto out; |
541 | 494 | ||
542 | /* | ||
543 | * Push GPIO specific irqdomain on hierarchy created as a side | ||
544 | * effect of the pci_enable_msix() | ||
545 | */ | ||
546 | txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, | ||
547 | 0, 0, of_node_to_fwnode(dev->of_node), | ||
548 | &thunderx_gpio_irqd_ops, txgpio); | ||
549 | if (!txgpio->irqd) { | ||
550 | err = -ENOMEM; | ||
551 | goto out; | ||
552 | } | ||
553 | |||
554 | /* Push on irq_data and the domain for each line. */ | ||
555 | for (i = 0; i < ngpio; i++) { | ||
556 | err = irq_domain_push_irq(txgpio->irqd, | ||
557 | txgpio->msix_entries[i].vector, | ||
558 | &txgpio->line_entries[i]); | ||
559 | if (err < 0) | ||
560 | dev_err(dev, "irq_domain_push_irq: %d\n", err); | ||
561 | } | ||
562 | |||
563 | chip->label = KBUILD_MODNAME; | 495 | chip->label = KBUILD_MODNAME; |
564 | chip->parent = dev; | 496 | chip->parent = dev; |
565 | chip->owner = THIS_MODULE; | 497 | chip->owner = THIS_MODULE; |
@@ -574,11 +506,28 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, | |||
574 | chip->set = thunderx_gpio_set; | 506 | chip->set = thunderx_gpio_set; |
575 | chip->set_multiple = thunderx_gpio_set_multiple; | 507 | chip->set_multiple = thunderx_gpio_set_multiple; |
576 | chip->set_config = thunderx_gpio_set_config; | 508 | chip->set_config = thunderx_gpio_set_config; |
577 | chip->to_irq = thunderx_gpio_to_irq; | 509 | girq = &chip->irq; |
510 | girq->chip = &thunderx_gpio_irq_chip; | ||
511 | girq->fwnode = of_node_to_fwnode(dev->of_node); | ||
512 | girq->parent_domain = | ||
513 | irq_get_irq_data(txgpio->msix_entries[0].vector)->domain; | ||
514 | girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq; | ||
515 | girq->handler = handle_bad_irq; | ||
516 | girq->default_type = IRQ_TYPE_NONE; | ||
517 | |||
578 | err = devm_gpiochip_add_data(dev, chip, txgpio); | 518 | err = devm_gpiochip_add_data(dev, chip, txgpio); |
579 | if (err) | 519 | if (err) |
580 | goto out; | 520 | goto out; |
581 | 521 | ||
522 | /* Push on irq_data and the domain for each line. */ | ||
523 | for (i = 0; i < ngpio; i++) { | ||
524 | err = irq_domain_push_irq(chip->irq.domain, | ||
525 | txgpio->msix_entries[i].vector, | ||
526 | chip); | ||
527 | if (err < 0) | ||
528 | dev_err(dev, "irq_domain_push_irq: %d\n", err); | ||
529 | } | ||
530 | |||
582 | dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n", | 531 | dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n", |
583 | ngpio, chip->base); | 532 | ngpio, chip->base); |
584 | return 0; | 533 | return 0; |
@@ -593,10 +542,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev) | |||
593 | struct thunderx_gpio *txgpio = pci_get_drvdata(pdev); | 542 | struct thunderx_gpio *txgpio = pci_get_drvdata(pdev); |
594 | 543 | ||
595 | for (i = 0; i < txgpio->chip.ngpio; i++) | 544 | for (i = 0; i < txgpio->chip.ngpio; i++) |
596 | irq_domain_pop_irq(txgpio->irqd, | 545 | irq_domain_pop_irq(txgpio->chip.irq.domain, |
597 | txgpio->msix_entries[i].vector); | 546 | txgpio->msix_entries[i].vector); |
598 | 547 | ||
599 | irq_domain_remove(txgpio->irqd); | 548 | irq_domain_remove(txgpio->chip.irq.domain); |
600 | 549 | ||
601 | pci_set_drvdata(pdev, NULL); | 550 | pci_set_drvdata(pdev, NULL); |
602 | } | 551 | } |