summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-thunderx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-thunderx.c')
-rw-r--r--drivers/gpio/gpio-thunderx.c163
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 {
53struct thunderx_gpio { 53struct 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
286static void thunderx_gpio_irq_ack(struct irq_data *data) 285static 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
294static void thunderx_gpio_irq_mask(struct irq_data *data) 294static 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
302static void thunderx_gpio_irq_mask_ack(struct irq_data *data) 303static 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
310static void thunderx_gpio_irq_unmask(struct irq_data *data) 312static 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
318static int thunderx_gpio_irq_set_type(struct irq_data *data, 321static 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
362static 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
379static 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
412static int thunderx_gpio_irq_translate(struct irq_domain *d, 388static 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
428static 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
437static const struct irq_domain_ops thunderx_gpio_irqd_ops = {
438 .alloc = thunderx_gpio_irq_alloc,
439 .translate = thunderx_gpio_irq_translate
440};
441
442static 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
449static int thunderx_gpio_probe(struct pci_dev *pdev, 401static 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}