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

memory: tegra: Parameterize interrupt handler

Tegra20 requires a slightly different interrupt handler than Tegra30 and
later, so parameterize the handler, so that each SoC implementation can
provide its own.

Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://lore.kernel.org/r/20210602163302.120041-8-thierry.reding@gmail.com
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>

authored by

Thierry Reding and committed by
Krzysztof Kozlowski
1079a66b ddeceab0

+106 -109
+27 -109
drivers/memory/tegra/mc.c
··· 492 492 return 0; 493 493 } 494 494 495 - const struct tegra_mc_ops tegra30_mc_ops = { 496 - .probe = tegra30_mc_probe, 497 - }; 498 - #endif 499 - 500 - static const char *const status_names[32] = { 501 - [ 1] = "External interrupt", 502 - [ 6] = "EMEM address decode error", 503 - [ 7] = "GART page fault", 504 - [ 8] = "Security violation", 505 - [ 9] = "EMEM arbitration error", 506 - [10] = "Page fault", 507 - [11] = "Invalid APB ASID update", 508 - [12] = "VPR violation", 509 - [13] = "Secure carveout violation", 510 - [16] = "MTS carveout violation", 511 - }; 512 - 513 - static const char *const error_names[8] = { 514 - [2] = "EMEM decode error", 515 - [3] = "TrustZone violation", 516 - [4] = "Carveout violation", 517 - [6] = "SMMU translation error", 518 - }; 519 - 520 - static irqreturn_t tegra_mc_irq(int irq, void *data) 495 + static irqreturn_t tegra30_mc_handle_irq(int irq, void *data) 521 496 { 522 497 struct tegra_mc *mc = data; 523 498 unsigned long status; ··· 504 529 return IRQ_NONE; 505 530 506 531 for_each_set_bit(bit, &status, 32) { 507 - const char *error = status_names[bit] ?: "unknown"; 532 + const char *error = tegra_mc_status_names[bit] ?: "unknown"; 508 533 const char *client = "unknown", *desc; 509 534 const char *direction, *secure; 510 535 phys_addr_t addr = 0; ··· 544 569 545 570 type = (value & MC_ERR_STATUS_TYPE_MASK) >> 546 571 MC_ERR_STATUS_TYPE_SHIFT; 547 - desc = error_names[type]; 572 + desc = tegra_mc_error_names[type]; 548 573 549 574 switch (value & MC_ERR_STATUS_TYPE_MASK) { 550 575 case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: ··· 589 614 return IRQ_HANDLED; 590 615 } 591 616 592 - static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) 593 - { 594 - struct tegra_mc *mc = data; 595 - unsigned long status; 596 - unsigned int bit; 617 + const struct tegra_mc_ops tegra30_mc_ops = { 618 + .probe = tegra30_mc_probe, 619 + .handle_irq = tegra30_mc_handle_irq, 620 + }; 621 + #endif 597 622 598 - /* mask all interrupts to avoid flooding */ 599 - status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; 600 - if (!status) 601 - return IRQ_NONE; 623 + const char *const tegra_mc_status_names[32] = { 624 + [ 1] = "External interrupt", 625 + [ 6] = "EMEM address decode error", 626 + [ 7] = "GART page fault", 627 + [ 8] = "Security violation", 628 + [ 9] = "EMEM arbitration error", 629 + [10] = "Page fault", 630 + [11] = "Invalid APB ASID update", 631 + [12] = "VPR violation", 632 + [13] = "Secure carveout violation", 633 + [16] = "MTS carveout violation", 634 + }; 602 635 603 - for_each_set_bit(bit, &status, 32) { 604 - const char *direction = "read", *secure = ""; 605 - const char *error = status_names[bit]; 606 - const char *client, *desc; 607 - phys_addr_t addr; 608 - u32 value, reg; 609 - u8 id, type; 610 - 611 - switch (BIT(bit)) { 612 - case MC_INT_DECERR_EMEM: 613 - reg = MC_DECERR_EMEM_OTHERS_STATUS; 614 - value = mc_readl(mc, reg); 615 - 616 - id = value & mc->soc->client_id_mask; 617 - desc = error_names[2]; 618 - 619 - if (value & BIT(31)) 620 - direction = "write"; 621 - break; 622 - 623 - case MC_INT_INVALID_GART_PAGE: 624 - reg = MC_GART_ERROR_REQ; 625 - value = mc_readl(mc, reg); 626 - 627 - id = (value >> 1) & mc->soc->client_id_mask; 628 - desc = error_names[2]; 629 - 630 - if (value & BIT(0)) 631 - direction = "write"; 632 - break; 633 - 634 - case MC_INT_SECURITY_VIOLATION: 635 - reg = MC_SECURITY_VIOLATION_STATUS; 636 - value = mc_readl(mc, reg); 637 - 638 - id = value & mc->soc->client_id_mask; 639 - type = (value & BIT(30)) ? 4 : 3; 640 - desc = error_names[type]; 641 - secure = "secure "; 642 - 643 - if (value & BIT(31)) 644 - direction = "write"; 645 - break; 646 - 647 - default: 648 - continue; 649 - } 650 - 651 - client = mc->soc->clients[id].name; 652 - addr = mc_readl(mc, reg + sizeof(u32)); 653 - 654 - dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", 655 - client, secure, direction, &addr, error, 656 - desc); 657 - } 658 - 659 - /* clear interrupts */ 660 - mc_writel(mc, status, MC_INTSTATUS); 661 - 662 - return IRQ_HANDLED; 663 - } 636 + const char *const tegra_mc_error_names[8] = { 637 + [2] = "EMEM decode error", 638 + [3] = "TrustZone violation", 639 + [4] = "Carveout violation", 640 + [6] = "SMMU translation error", 641 + }; 664 642 665 643 /* 666 644 * Memory Controller (MC) has few Memory Clients that are issuing memory ··· 714 786 { 715 787 struct resource *res; 716 788 struct tegra_mc *mc; 717 - void *isr; 718 789 u64 mask; 719 790 int err; 720 791 ··· 750 823 return err; 751 824 } 752 825 753 - #ifdef CONFIG_ARCH_TEGRA_2x_SOC 754 - if (mc->soc == &tegra20_mc_soc) { 755 - isr = tegra20_mc_irq; 756 - } else 757 - #endif 758 - { 759 - isr = tegra_mc_irq; 760 - } 761 - 762 826 mc->irq = platform_get_irq(pdev, 0); 763 827 if (mc->irq < 0) 764 828 return mc->irq; ··· 758 840 759 841 mc_writel(mc, mc->soc->intmask, MC_INTMASK); 760 842 761 - err = devm_request_irq(&pdev->dev, mc->irq, isr, 0, 843 + err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0, 762 844 dev_name(&pdev->dev), mc); 763 845 if (err < 0) { 764 846 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
+3
drivers/memory/tegra/mc.h
··· 138 138 extern const struct tegra_mc_ops tegra30_mc_ops; 139 139 #endif 140 140 141 + extern const char * const tegra_mc_status_names[32]; 142 + extern const char * const tegra_mc_error_names[8]; 143 + 141 144 /* 142 145 * These IDs are for internal use of Tegra ICC drivers. The ID numbers are 143 146 * chosen such that they don't conflict with the device-tree ICC node IDs.
+74
drivers/memory/tegra/tegra20.c
··· 713 713 return 0; 714 714 } 715 715 716 + static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) 717 + { 718 + struct tegra_mc *mc = data; 719 + unsigned long status; 720 + unsigned int bit; 721 + 722 + /* mask all interrupts to avoid flooding */ 723 + status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; 724 + if (!status) 725 + return IRQ_NONE; 726 + 727 + for_each_set_bit(bit, &status, 32) { 728 + const char *error = tegra_mc_status_names[bit]; 729 + const char *direction = "read", *secure = ""; 730 + const char *client, *desc; 731 + phys_addr_t addr; 732 + u32 value, reg; 733 + u8 id, type; 734 + 735 + switch (BIT(bit)) { 736 + case MC_INT_DECERR_EMEM: 737 + reg = MC_DECERR_EMEM_OTHERS_STATUS; 738 + value = mc_readl(mc, reg); 739 + 740 + id = value & mc->soc->client_id_mask; 741 + desc = tegra_mc_error_names[2]; 742 + 743 + if (value & BIT(31)) 744 + direction = "write"; 745 + break; 746 + 747 + case MC_INT_INVALID_GART_PAGE: 748 + reg = MC_GART_ERROR_REQ; 749 + value = mc_readl(mc, reg); 750 + 751 + id = (value >> 1) & mc->soc->client_id_mask; 752 + desc = tegra_mc_error_names[2]; 753 + 754 + if (value & BIT(0)) 755 + direction = "write"; 756 + break; 757 + 758 + case MC_INT_SECURITY_VIOLATION: 759 + reg = MC_SECURITY_VIOLATION_STATUS; 760 + value = mc_readl(mc, reg); 761 + 762 + id = value & mc->soc->client_id_mask; 763 + type = (value & BIT(30)) ? 4 : 3; 764 + desc = tegra_mc_error_names[type]; 765 + secure = "secure "; 766 + 767 + if (value & BIT(31)) 768 + direction = "write"; 769 + break; 770 + 771 + default: 772 + continue; 773 + } 774 + 775 + client = mc->soc->clients[id].name; 776 + addr = mc_readl(mc, reg + sizeof(u32)); 777 + 778 + dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", 779 + client, secure, direction, &addr, error, 780 + desc); 781 + } 782 + 783 + /* clear interrupts */ 784 + mc_writel(mc, status, MC_INTSTATUS); 785 + 786 + return IRQ_HANDLED; 787 + } 788 + 716 789 static const struct tegra_mc_ops tegra20_mc_ops = { 717 790 .probe = tegra20_mc_probe, 718 791 .suspend = tegra20_mc_suspend, 719 792 .resume = tegra20_mc_resume, 793 + .handle_irq = tegra20_mc_handle_irq, 720 794 }; 721 795 722 796 const struct tegra_mc_soc tegra20_mc_soc = {
+2
include/soc/tegra/mc.h
··· 10 10 #include <linux/debugfs.h> 11 11 #include <linux/err.h> 12 12 #include <linux/interconnect-provider.h> 13 + #include <linux/irq.h> 13 14 #include <linux/reset-controller.h> 14 15 #include <linux/types.h> 15 16 ··· 178 177 int (*probe)(struct tegra_mc *mc); 179 178 int (*suspend)(struct tegra_mc *mc); 180 179 int (*resume)(struct tegra_mc *mc); 180 + irqreturn_t (*handle_irq)(int irq, void *data); 181 181 }; 182 182 183 183 struct tegra_mc_soc {