| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Support PCI/PCIe on PowerNV platforms |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright 2011 Benjamin Herrenschmidt, IBM Corp. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 38 | 34 | #include "powernv.h" |
|---|
| 39 | 35 | #include "pci.h" |
|---|
| 40 | 36 | |
|---|
| 41 | | -static DEFINE_MUTEX(p2p_mutex); |
|---|
| 42 | 37 | static DEFINE_MUTEX(tunnel_mutex); |
|---|
| 43 | 38 | |
|---|
| 44 | 39 | int pnv_pci_get_slot_id(struct device_node *np, uint64_t *id) |
|---|
| 45 | 40 | { |
|---|
| 46 | | - struct device_node *parent = np; |
|---|
| 41 | + struct device_node *node = np; |
|---|
| 47 | 42 | u32 bdfn; |
|---|
| 48 | 43 | u64 phbid; |
|---|
| 49 | 44 | int ret; |
|---|
| .. | .. |
|---|
| 53 | 48 | return -ENXIO; |
|---|
| 54 | 49 | |
|---|
| 55 | 50 | bdfn = ((bdfn & 0x00ffff00) >> 8); |
|---|
| 56 | | - while ((parent = of_get_parent(parent))) { |
|---|
| 57 | | - if (!PCI_DN(parent)) { |
|---|
| 58 | | - of_node_put(parent); |
|---|
| 51 | + for (node = np; node; node = of_get_parent(node)) { |
|---|
| 52 | + if (!PCI_DN(node)) { |
|---|
| 53 | + of_node_put(node); |
|---|
| 59 | 54 | break; |
|---|
| 60 | 55 | } |
|---|
| 61 | 56 | |
|---|
| 62 | | - if (!of_device_is_compatible(parent, "ibm,ioda2-phb")) { |
|---|
| 63 | | - of_node_put(parent); |
|---|
| 57 | + if (!of_device_is_compatible(node, "ibm,ioda2-phb") && |
|---|
| 58 | + !of_device_is_compatible(node, "ibm,ioda3-phb") && |
|---|
| 59 | + !of_device_is_compatible(node, "ibm,ioda2-npu2-opencapi-phb")) { |
|---|
| 60 | + of_node_put(node); |
|---|
| 64 | 61 | continue; |
|---|
| 65 | 62 | } |
|---|
| 66 | 63 | |
|---|
| 67 | | - ret = of_property_read_u64(parent, "ibm,opal-phbid", &phbid); |
|---|
| 64 | + ret = of_property_read_u64(node, "ibm,opal-phbid", &phbid); |
|---|
| 68 | 65 | if (ret) { |
|---|
| 69 | | - of_node_put(parent); |
|---|
| 66 | + of_node_put(node); |
|---|
| 70 | 67 | return -ENXIO; |
|---|
| 71 | 68 | } |
|---|
| 72 | 69 | |
|---|
| 73 | | - *id = PCI_SLOT_ID(phbid, bdfn); |
|---|
| 70 | + if (of_device_is_compatible(node, "ibm,ioda2-npu2-opencapi-phb")) |
|---|
| 71 | + *id = PCI_PHB_SLOT_ID(phbid); |
|---|
| 72 | + else |
|---|
| 73 | + *id = PCI_SLOT_ID(phbid, bdfn); |
|---|
| 74 | 74 | return 0; |
|---|
| 75 | 75 | } |
|---|
| 76 | 76 | |
|---|
| .. | .. |
|---|
| 160 | 160 | } |
|---|
| 161 | 161 | EXPORT_SYMBOL_GPL(pnv_pci_set_power_state); |
|---|
| 162 | 162 | |
|---|
| 163 | | -#ifdef CONFIG_PCI_MSI |
|---|
| 164 | 163 | int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) |
|---|
| 165 | 164 | { |
|---|
| 166 | | - struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
|---|
| 167 | | - struct pnv_phb *phb = hose->private_data; |
|---|
| 165 | + struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus); |
|---|
| 168 | 166 | struct msi_desc *entry; |
|---|
| 169 | 167 | struct msi_msg msg; |
|---|
| 170 | 168 | int hwirq; |
|---|
| .. | .. |
|---|
| 212 | 210 | |
|---|
| 213 | 211 | void pnv_teardown_msi_irqs(struct pci_dev *pdev) |
|---|
| 214 | 212 | { |
|---|
| 215 | | - struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
|---|
| 216 | | - struct pnv_phb *phb = hose->private_data; |
|---|
| 213 | + struct pnv_phb *phb = pci_bus_to_pnvhb(pdev->bus); |
|---|
| 217 | 214 | struct msi_desc *entry; |
|---|
| 218 | 215 | irq_hw_number_t hwirq; |
|---|
| 219 | 216 | |
|---|
| .. | .. |
|---|
| 229 | 226 | msi_bitmap_free_hwirqs(&phb->msi_bmp, hwirq - phb->msi_base, 1); |
|---|
| 230 | 227 | } |
|---|
| 231 | 228 | } |
|---|
| 232 | | -#endif /* CONFIG_PCI_MSI */ |
|---|
| 233 | 229 | |
|---|
| 234 | 230 | /* Nicely print the contents of the PE State Tables (PEST). */ |
|---|
| 235 | 231 | static void pnv_pci_dump_pest(__be64 pestA[], __be64 pestB[], int pest_size) |
|---|
| .. | .. |
|---|
| 816 | 812 | return tbl; |
|---|
| 817 | 813 | } |
|---|
| 818 | 814 | |
|---|
| 819 | | -void pnv_pci_dma_dev_setup(struct pci_dev *pdev) |
|---|
| 820 | | -{ |
|---|
| 821 | | - struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
|---|
| 822 | | - struct pnv_phb *phb = hose->private_data; |
|---|
| 823 | | - |
|---|
| 824 | | - if (phb && phb->dma_dev_setup) |
|---|
| 825 | | - phb->dma_dev_setup(phb, pdev); |
|---|
| 826 | | -} |
|---|
| 827 | | - |
|---|
| 828 | | -void pnv_pci_dma_bus_setup(struct pci_bus *bus) |
|---|
| 829 | | -{ |
|---|
| 830 | | - struct pci_controller *hose = bus->sysdata; |
|---|
| 831 | | - struct pnv_phb *phb = hose->private_data; |
|---|
| 832 | | - struct pnv_ioda_pe *pe; |
|---|
| 833 | | - |
|---|
| 834 | | - list_for_each_entry(pe, &phb->ioda.pe_list, list) { |
|---|
| 835 | | - if (!(pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))) |
|---|
| 836 | | - continue; |
|---|
| 837 | | - |
|---|
| 838 | | - if (!pe->pbus) |
|---|
| 839 | | - continue; |
|---|
| 840 | | - |
|---|
| 841 | | - if (bus->number == ((pe->rid >> 8) & 0xFF)) { |
|---|
| 842 | | - pe->pbus = bus; |
|---|
| 843 | | - break; |
|---|
| 844 | | - } |
|---|
| 845 | | - } |
|---|
| 846 | | -} |
|---|
| 847 | | - |
|---|
| 848 | | -int pnv_pci_set_p2p(struct pci_dev *initiator, struct pci_dev *target, u64 desc) |
|---|
| 849 | | -{ |
|---|
| 850 | | - struct pci_controller *hose; |
|---|
| 851 | | - struct pnv_phb *phb_init, *phb_target; |
|---|
| 852 | | - struct pnv_ioda_pe *pe_init; |
|---|
| 853 | | - int rc; |
|---|
| 854 | | - |
|---|
| 855 | | - if (!opal_check_token(OPAL_PCI_SET_P2P)) |
|---|
| 856 | | - return -ENXIO; |
|---|
| 857 | | - |
|---|
| 858 | | - hose = pci_bus_to_host(initiator->bus); |
|---|
| 859 | | - phb_init = hose->private_data; |
|---|
| 860 | | - |
|---|
| 861 | | - hose = pci_bus_to_host(target->bus); |
|---|
| 862 | | - phb_target = hose->private_data; |
|---|
| 863 | | - |
|---|
| 864 | | - pe_init = pnv_ioda_get_pe(initiator); |
|---|
| 865 | | - if (!pe_init) |
|---|
| 866 | | - return -ENODEV; |
|---|
| 867 | | - |
|---|
| 868 | | - /* |
|---|
| 869 | | - * Configuring the initiator's PHB requires to adjust its |
|---|
| 870 | | - * TVE#1 setting. Since the same device can be an initiator |
|---|
| 871 | | - * several times for different target devices, we need to keep |
|---|
| 872 | | - * a reference count to know when we can restore the default |
|---|
| 873 | | - * bypass setting on its TVE#1 when disabling. Opal is not |
|---|
| 874 | | - * tracking PE states, so we add a reference count on the PE |
|---|
| 875 | | - * in linux. |
|---|
| 876 | | - * |
|---|
| 877 | | - * For the target, the configuration is per PHB, so we keep a |
|---|
| 878 | | - * target reference count on the PHB. |
|---|
| 879 | | - */ |
|---|
| 880 | | - mutex_lock(&p2p_mutex); |
|---|
| 881 | | - |
|---|
| 882 | | - if (desc & OPAL_PCI_P2P_ENABLE) { |
|---|
| 883 | | - /* always go to opal to validate the configuration */ |
|---|
| 884 | | - rc = opal_pci_set_p2p(phb_init->opal_id, phb_target->opal_id, |
|---|
| 885 | | - desc, pe_init->pe_number); |
|---|
| 886 | | - |
|---|
| 887 | | - if (rc != OPAL_SUCCESS) { |
|---|
| 888 | | - rc = -EIO; |
|---|
| 889 | | - goto out; |
|---|
| 890 | | - } |
|---|
| 891 | | - |
|---|
| 892 | | - pe_init->p2p_initiator_count++; |
|---|
| 893 | | - phb_target->p2p_target_count++; |
|---|
| 894 | | - } else { |
|---|
| 895 | | - if (!pe_init->p2p_initiator_count || |
|---|
| 896 | | - !phb_target->p2p_target_count) { |
|---|
| 897 | | - rc = -EINVAL; |
|---|
| 898 | | - goto out; |
|---|
| 899 | | - } |
|---|
| 900 | | - |
|---|
| 901 | | - if (--pe_init->p2p_initiator_count == 0) |
|---|
| 902 | | - pnv_pci_ioda2_set_bypass(pe_init, true); |
|---|
| 903 | | - |
|---|
| 904 | | - if (--phb_target->p2p_target_count == 0) { |
|---|
| 905 | | - rc = opal_pci_set_p2p(phb_init->opal_id, |
|---|
| 906 | | - phb_target->opal_id, desc, |
|---|
| 907 | | - pe_init->pe_number); |
|---|
| 908 | | - if (rc != OPAL_SUCCESS) { |
|---|
| 909 | | - rc = -EIO; |
|---|
| 910 | | - goto out; |
|---|
| 911 | | - } |
|---|
| 912 | | - } |
|---|
| 913 | | - } |
|---|
| 914 | | - rc = 0; |
|---|
| 915 | | -out: |
|---|
| 916 | | - mutex_unlock(&p2p_mutex); |
|---|
| 917 | | - return rc; |
|---|
| 918 | | -} |
|---|
| 919 | | -EXPORT_SYMBOL_GPL(pnv_pci_set_p2p); |
|---|
| 920 | | - |
|---|
| 921 | 815 | struct device_node *pnv_pci_get_phb_node(struct pci_dev *dev) |
|---|
| 922 | 816 | { |
|---|
| 923 | 817 | struct pci_controller *hose = pci_bus_to_host(dev->bus); |
|---|
| .. | .. |
|---|
| 926 | 820 | } |
|---|
| 927 | 821 | EXPORT_SYMBOL(pnv_pci_get_phb_node); |
|---|
| 928 | 822 | |
|---|
| 929 | | -int pnv_pci_enable_tunnel(struct pci_dev *dev, u64 *asnind) |
|---|
| 930 | | -{ |
|---|
| 931 | | - struct device_node *np; |
|---|
| 932 | | - const __be32 *prop; |
|---|
| 933 | | - struct pnv_ioda_pe *pe; |
|---|
| 934 | | - uint16_t window_id; |
|---|
| 935 | | - int rc; |
|---|
| 936 | | - |
|---|
| 937 | | - if (!radix_enabled()) |
|---|
| 938 | | - return -ENXIO; |
|---|
| 939 | | - |
|---|
| 940 | | - if (!(np = pnv_pci_get_phb_node(dev))) |
|---|
| 941 | | - return -ENXIO; |
|---|
| 942 | | - |
|---|
| 943 | | - prop = of_get_property(np, "ibm,phb-indications", NULL); |
|---|
| 944 | | - of_node_put(np); |
|---|
| 945 | | - |
|---|
| 946 | | - if (!prop || !prop[1]) |
|---|
| 947 | | - return -ENXIO; |
|---|
| 948 | | - |
|---|
| 949 | | - *asnind = (u64)be32_to_cpu(prop[1]); |
|---|
| 950 | | - pe = pnv_ioda_get_pe(dev); |
|---|
| 951 | | - if (!pe) |
|---|
| 952 | | - return -ENODEV; |
|---|
| 953 | | - |
|---|
| 954 | | - /* Increase real window size to accept as_notify messages. */ |
|---|
| 955 | | - window_id = (pe->pe_number << 1 ) + 1; |
|---|
| 956 | | - rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id, pe->pe_number, |
|---|
| 957 | | - window_id, pe->tce_bypass_base, |
|---|
| 958 | | - (uint64_t)1 << 48); |
|---|
| 959 | | - return opal_error_code(rc); |
|---|
| 960 | | -} |
|---|
| 961 | | -EXPORT_SYMBOL_GPL(pnv_pci_enable_tunnel); |
|---|
| 962 | | - |
|---|
| 963 | | -int pnv_pci_disable_tunnel(struct pci_dev *dev) |
|---|
| 964 | | -{ |
|---|
| 965 | | - struct pnv_ioda_pe *pe; |
|---|
| 966 | | - |
|---|
| 967 | | - pe = pnv_ioda_get_pe(dev); |
|---|
| 968 | | - if (!pe) |
|---|
| 969 | | - return -ENODEV; |
|---|
| 970 | | - |
|---|
| 971 | | - /* Restore default real window size. */ |
|---|
| 972 | | - pnv_pci_ioda2_set_bypass(pe, true); |
|---|
| 973 | | - return 0; |
|---|
| 974 | | -} |
|---|
| 975 | | -EXPORT_SYMBOL_GPL(pnv_pci_disable_tunnel); |
|---|
| 976 | | - |
|---|
| 977 | 823 | int pnv_pci_set_tunnel_bar(struct pci_dev *dev, u64 addr, int enable) |
|---|
| 978 | 824 | { |
|---|
| 979 | | - __be64 val; |
|---|
| 980 | | - struct pci_controller *hose; |
|---|
| 981 | | - struct pnv_phb *phb; |
|---|
| 825 | + struct pnv_phb *phb = pci_bus_to_pnvhb(dev->bus); |
|---|
| 982 | 826 | u64 tunnel_bar; |
|---|
| 827 | + __be64 val; |
|---|
| 983 | 828 | int rc; |
|---|
| 984 | 829 | |
|---|
| 985 | 830 | if (!opal_check_token(OPAL_PCI_GET_PBCQ_TUNNEL_BAR)) |
|---|
| 986 | 831 | return -ENXIO; |
|---|
| 987 | 832 | if (!opal_check_token(OPAL_PCI_SET_PBCQ_TUNNEL_BAR)) |
|---|
| 988 | 833 | return -ENXIO; |
|---|
| 989 | | - |
|---|
| 990 | | - hose = pci_bus_to_host(dev->bus); |
|---|
| 991 | | - phb = hose->private_data; |
|---|
| 992 | 834 | |
|---|
| 993 | 835 | mutex_lock(&tunnel_mutex); |
|---|
| 994 | 836 | rc = opal_pci_get_pbcq_tunnel_bar(phb->opal_id, &val); |
|---|
| .. | .. |
|---|
| 1027 | 869 | return rc; |
|---|
| 1028 | 870 | } |
|---|
| 1029 | 871 | EXPORT_SYMBOL_GPL(pnv_pci_set_tunnel_bar); |
|---|
| 1030 | | - |
|---|
| 1031 | | -#ifdef CONFIG_PPC64 /* for thread.tidr */ |
|---|
| 1032 | | -int pnv_pci_get_as_notify_info(struct task_struct *task, u32 *lpid, u32 *pid, |
|---|
| 1033 | | - u32 *tid) |
|---|
| 1034 | | -{ |
|---|
| 1035 | | - struct mm_struct *mm = NULL; |
|---|
| 1036 | | - |
|---|
| 1037 | | - if (task == NULL) |
|---|
| 1038 | | - return -EINVAL; |
|---|
| 1039 | | - |
|---|
| 1040 | | - mm = get_task_mm(task); |
|---|
| 1041 | | - if (mm == NULL) |
|---|
| 1042 | | - return -EINVAL; |
|---|
| 1043 | | - |
|---|
| 1044 | | - *pid = mm->context.id; |
|---|
| 1045 | | - mmput(mm); |
|---|
| 1046 | | - |
|---|
| 1047 | | - *tid = task->thread.tidr; |
|---|
| 1048 | | - *lpid = mfspr(SPRN_LPID); |
|---|
| 1049 | | - return 0; |
|---|
| 1050 | | -} |
|---|
| 1051 | | -EXPORT_SYMBOL_GPL(pnv_pci_get_as_notify_info); |
|---|
| 1052 | | -#endif |
|---|
| 1053 | 872 | |
|---|
| 1054 | 873 | void pnv_pci_shutdown(void) |
|---|
| 1055 | 874 | { |
|---|
| .. | .. |
|---|
| 1126 | 945 | set_pci_dma_ops(&dma_iommu_ops); |
|---|
| 1127 | 946 | } |
|---|
| 1128 | 947 | |
|---|
| 1129 | | -machine_subsys_initcall_sync(powernv, tce_iommu_bus_notifier_init); |
|---|
| 948 | +static int pnv_tce_iommu_bus_notifier(struct notifier_block *nb, |
|---|
| 949 | + unsigned long action, void *data) |
|---|
| 950 | +{ |
|---|
| 951 | + struct device *dev = data; |
|---|
| 952 | + |
|---|
| 953 | + switch (action) { |
|---|
| 954 | + case BUS_NOTIFY_DEL_DEVICE: |
|---|
| 955 | + iommu_del_device(dev); |
|---|
| 956 | + return 0; |
|---|
| 957 | + default: |
|---|
| 958 | + return 0; |
|---|
| 959 | + } |
|---|
| 960 | +} |
|---|
| 961 | + |
|---|
| 962 | +static struct notifier_block pnv_tce_iommu_bus_nb = { |
|---|
| 963 | + .notifier_call = pnv_tce_iommu_bus_notifier, |
|---|
| 964 | +}; |
|---|
| 965 | + |
|---|
| 966 | +static int __init pnv_tce_iommu_bus_notifier_init(void) |
|---|
| 967 | +{ |
|---|
| 968 | + bus_register_notifier(&pci_bus_type, &pnv_tce_iommu_bus_nb); |
|---|
| 969 | + return 0; |
|---|
| 970 | +} |
|---|
| 971 | +machine_subsys_initcall_sync(powernv, pnv_tce_iommu_bus_notifier_init); |
|---|