.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Copyright (C) 2006 Olof Johansson <olof@lixom.net> |
---|
8 | 9 | * |
---|
9 | 10 | * Dynamic DMA mapping support, pSeries-specific parts, both SMP and LPAR. |
---|
10 | | - * |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify |
---|
13 | | - * it under the terms of the GNU General Public License as published by |
---|
14 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
15 | | - * (at your option) any later version. |
---|
16 | | - * |
---|
17 | | - * This program is distributed in the hope that it will be useful, |
---|
18 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
19 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
20 | | - * GNU General Public License for more details. |
---|
21 | | - * |
---|
22 | | - * You should have received a copy of the GNU General Public License |
---|
23 | | - * along with this program; if not, write to the Free Software |
---|
24 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
25 | 11 | */ |
---|
26 | 12 | |
---|
27 | 13 | #include <linux/init.h> |
---|
.. | .. |
---|
53 | 39 | |
---|
54 | 40 | #include "pseries.h" |
---|
55 | 41 | |
---|
| 42 | +enum { |
---|
| 43 | + DDW_QUERY_PE_DMA_WIN = 0, |
---|
| 44 | + DDW_CREATE_PE_DMA_WIN = 1, |
---|
| 45 | + DDW_REMOVE_PE_DMA_WIN = 2, |
---|
| 46 | + |
---|
| 47 | + DDW_APPLICABLE_SIZE |
---|
| 48 | +}; |
---|
| 49 | + |
---|
| 50 | +enum { |
---|
| 51 | + DDW_EXT_SIZE = 0, |
---|
| 52 | + DDW_EXT_RESET_DMA_WIN = 1, |
---|
| 53 | + DDW_EXT_QUERY_OUT_SIZE = 2 |
---|
| 54 | +}; |
---|
| 55 | + |
---|
56 | 56 | static struct iommu_table_group *iommu_pseries_alloc_group(int node) |
---|
57 | 57 | { |
---|
58 | 58 | struct iommu_table_group *table_group; |
---|
59 | 59 | struct iommu_table *tbl; |
---|
60 | | - struct iommu_table_group_link *tgl; |
---|
61 | 60 | |
---|
62 | 61 | table_group = kzalloc_node(sizeof(struct iommu_table_group), GFP_KERNEL, |
---|
63 | 62 | node); |
---|
.. | .. |
---|
68 | 67 | if (!tbl) |
---|
69 | 68 | goto free_group; |
---|
70 | 69 | |
---|
71 | | - tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL, |
---|
72 | | - node); |
---|
73 | | - if (!tgl) |
---|
74 | | - goto free_table; |
---|
75 | | - |
---|
76 | 70 | INIT_LIST_HEAD_RCU(&tbl->it_group_list); |
---|
77 | 71 | kref_init(&tbl->it_kref); |
---|
78 | | - tgl->table_group = table_group; |
---|
79 | | - list_add_rcu(&tgl->next, &tbl->it_group_list); |
---|
80 | 72 | |
---|
81 | 73 | table_group->tables[0] = tbl; |
---|
82 | 74 | |
---|
83 | 75 | return table_group; |
---|
84 | 76 | |
---|
85 | | -free_table: |
---|
86 | | - kfree(tbl); |
---|
87 | 77 | free_group: |
---|
88 | 78 | kfree(table_group); |
---|
89 | 79 | return NULL; |
---|
.. | .. |
---|
93 | 83 | const char *node_name) |
---|
94 | 84 | { |
---|
95 | 85 | struct iommu_table *tbl; |
---|
96 | | -#ifdef CONFIG_IOMMU_API |
---|
97 | | - struct iommu_table_group_link *tgl; |
---|
98 | | -#endif |
---|
99 | 86 | |
---|
100 | 87 | if (!table_group) |
---|
101 | 88 | return; |
---|
102 | 89 | |
---|
103 | 90 | tbl = table_group->tables[0]; |
---|
104 | 91 | #ifdef CONFIG_IOMMU_API |
---|
105 | | - tgl = list_first_entry_or_null(&tbl->it_group_list, |
---|
106 | | - struct iommu_table_group_link, next); |
---|
107 | | - |
---|
108 | | - WARN_ON_ONCE(!tgl); |
---|
109 | | - if (tgl) { |
---|
110 | | - list_del_rcu(&tgl->next); |
---|
111 | | - kfree(tgl); |
---|
112 | | - } |
---|
113 | 92 | if (table_group->group) { |
---|
114 | 93 | iommu_group_put(table_group->group); |
---|
115 | 94 | BUG_ON(table_group->group); |
---|
.. | .. |
---|
126 | 105 | unsigned long attrs) |
---|
127 | 106 | { |
---|
128 | 107 | u64 proto_tce; |
---|
129 | | - __be64 *tcep, *tces; |
---|
| 108 | + __be64 *tcep; |
---|
130 | 109 | u64 rpn; |
---|
131 | 110 | |
---|
132 | 111 | proto_tce = TCE_PCI_READ; // Read allowed |
---|
.. | .. |
---|
134 | 113 | if (direction != DMA_TO_DEVICE) |
---|
135 | 114 | proto_tce |= TCE_PCI_WRITE; |
---|
136 | 115 | |
---|
137 | | - tces = tcep = ((__be64 *)tbl->it_base) + index; |
---|
| 116 | + tcep = ((__be64 *)tbl->it_base) + index; |
---|
138 | 117 | |
---|
139 | 118 | while (npages--) { |
---|
140 | 119 | /* can't move this out since we might cross MEMBLOCK boundary */ |
---|
.. | .. |
---|
150 | 129 | |
---|
151 | 130 | static void tce_free_pSeries(struct iommu_table *tbl, long index, long npages) |
---|
152 | 131 | { |
---|
153 | | - __be64 *tcep, *tces; |
---|
| 132 | + __be64 *tcep; |
---|
154 | 133 | |
---|
155 | | - tces = tcep = ((__be64 *)tbl->it_base) + index; |
---|
| 134 | + tcep = ((__be64 *)tbl->it_base) + index; |
---|
156 | 135 | |
---|
157 | 136 | while (npages--) |
---|
158 | 137 | *(tcep++) = 0; |
---|
.. | .. |
---|
227 | 206 | int ret = 0; |
---|
228 | 207 | unsigned long flags; |
---|
229 | 208 | |
---|
230 | | - if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) { |
---|
| 209 | + if ((npages == 1) || !firmware_has_feature(FW_FEATURE_PUT_TCE_IND)) { |
---|
231 | 210 | return tce_build_pSeriesLP(tbl->it_index, tcenum, |
---|
232 | 211 | tbl->it_page_shift, npages, uaddr, |
---|
233 | 212 | direction, attrs); |
---|
.. | .. |
---|
321 | 300 | { |
---|
322 | 301 | u64 rc; |
---|
323 | 302 | |
---|
324 | | - if (!firmware_has_feature(FW_FEATURE_MULTITCE)) |
---|
| 303 | + if (!firmware_has_feature(FW_FEATURE_STUFF_TCE)) |
---|
325 | 304 | return tce_free_pSeriesLP(tbl->it_index, tcenum, npages); |
---|
326 | 305 | |
---|
327 | 306 | rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages); |
---|
.. | .. |
---|
369 | 348 | /* Dynamic DMA Window support */ |
---|
370 | 349 | struct ddw_query_response { |
---|
371 | 350 | u32 windows_available; |
---|
372 | | - u32 largest_available_block; |
---|
| 351 | + u64 largest_available_block; |
---|
373 | 352 | u32 page_size; |
---|
374 | 353 | u32 migration_capable; |
---|
375 | 354 | }; |
---|
.. | .. |
---|
437 | 416 | u64 rc = 0; |
---|
438 | 417 | long l, limit; |
---|
439 | 418 | |
---|
440 | | - if (!firmware_has_feature(FW_FEATURE_MULTITCE)) { |
---|
| 419 | + if (!firmware_has_feature(FW_FEATURE_PUT_TCE_IND)) { |
---|
441 | 420 | unsigned long tceshift = be32_to_cpu(maprange->tce_shift); |
---|
442 | 421 | unsigned long dmastart = (start_pfn << PAGE_SHIFT) + |
---|
443 | 422 | be64_to_cpu(maprange->dma_base); |
---|
.. | .. |
---|
659 | 638 | |
---|
660 | 639 | iommu_table_setparms(pci->phb, dn, tbl); |
---|
661 | 640 | tbl->it_ops = &iommu_table_pseries_ops; |
---|
662 | | - iommu_init_table(tbl, pci->phb->node); |
---|
663 | | - iommu_register_group(pci->table_group, pci_domain_nr(bus), 0); |
---|
| 641 | + iommu_init_table(tbl, pci->phb->node, 0, 0); |
---|
664 | 642 | |
---|
665 | 643 | /* Divide the rest (1.75GB) among the children */ |
---|
666 | 644 | pci->phb->dma_window_size = 0x80000000ul; |
---|
.. | .. |
---|
672 | 650 | |
---|
673 | 651 | #ifdef CONFIG_IOMMU_API |
---|
674 | 652 | static int tce_exchange_pseries(struct iommu_table *tbl, long index, unsigned |
---|
675 | | - long *tce, enum dma_data_direction *direction) |
---|
| 653 | + long *tce, enum dma_data_direction *direction, |
---|
| 654 | + bool realmode) |
---|
676 | 655 | { |
---|
677 | 656 | long rc; |
---|
678 | 657 | unsigned long ioba = (unsigned long) index << tbl->it_page_shift; |
---|
.. | .. |
---|
700 | 679 | struct iommu_table_ops iommu_table_lpar_multi_ops = { |
---|
701 | 680 | .set = tce_buildmulti_pSeriesLP, |
---|
702 | 681 | #ifdef CONFIG_IOMMU_API |
---|
703 | | - .exchange = tce_exchange_pseries, |
---|
| 682 | + .xchg_no_kill = tce_exchange_pseries, |
---|
704 | 683 | #endif |
---|
705 | 684 | .clear = tce_freemulti_pSeriesLP, |
---|
706 | 685 | .get = tce_get_pSeriesLP |
---|
.. | .. |
---|
741 | 720 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, |
---|
742 | 721 | ppci->table_group, dma_window); |
---|
743 | 722 | tbl->it_ops = &iommu_table_lpar_multi_ops; |
---|
744 | | - iommu_init_table(tbl, ppci->phb->node); |
---|
| 723 | + iommu_init_table(tbl, ppci->phb->node, 0, 0); |
---|
745 | 724 | iommu_register_group(ppci->table_group, |
---|
746 | 725 | pci_domain_nr(bus), 0); |
---|
747 | 726 | pr_debug(" created table: %p\n", ppci->table_group); |
---|
.. | .. |
---|
770 | 749 | tbl = PCI_DN(dn)->table_group->tables[0]; |
---|
771 | 750 | iommu_table_setparms(phb, dn, tbl); |
---|
772 | 751 | tbl->it_ops = &iommu_table_pseries_ops; |
---|
773 | | - iommu_init_table(tbl, phb->node); |
---|
774 | | - iommu_register_group(PCI_DN(dn)->table_group, |
---|
775 | | - pci_domain_nr(phb->bus), 0); |
---|
| 752 | + iommu_init_table(tbl, phb->node, 0, 0); |
---|
776 | 753 | set_iommu_table_base(&dev->dev, tbl); |
---|
777 | | - iommu_add_device(&dev->dev); |
---|
778 | 754 | return; |
---|
779 | 755 | } |
---|
780 | 756 | |
---|
.. | .. |
---|
785 | 761 | while (dn && PCI_DN(dn) && PCI_DN(dn)->table_group == NULL) |
---|
786 | 762 | dn = dn->parent; |
---|
787 | 763 | |
---|
788 | | - if (dn && PCI_DN(dn)) { |
---|
| 764 | + if (dn && PCI_DN(dn)) |
---|
789 | 765 | set_iommu_table_base(&dev->dev, |
---|
790 | 766 | PCI_DN(dn)->table_group->tables[0]); |
---|
791 | | - iommu_add_device(&dev->dev); |
---|
792 | | - } else |
---|
| 767 | + else |
---|
793 | 768 | printk(KERN_WARNING "iommu: Device %s has no iommu table\n", |
---|
794 | 769 | pci_name(dev)); |
---|
795 | 770 | } |
---|
.. | .. |
---|
806 | 781 | |
---|
807 | 782 | early_param("disable_ddw", disable_ddw_setup); |
---|
808 | 783 | |
---|
809 | | -static void remove_ddw(struct device_node *np, bool remove_prop) |
---|
| 784 | +static void remove_dma_window(struct device_node *np, u32 *ddw_avail, |
---|
| 785 | + struct property *win) |
---|
810 | 786 | { |
---|
811 | 787 | struct dynamic_dma_window_prop *dwp; |
---|
812 | | - struct property *win64; |
---|
813 | | - u32 ddw_avail[3]; |
---|
814 | 788 | u64 liobn; |
---|
815 | | - int ret = 0; |
---|
| 789 | + int ret; |
---|
816 | 790 | |
---|
817 | | - ret = of_property_read_u32_array(np, "ibm,ddw-applicable", |
---|
818 | | - &ddw_avail[0], 3); |
---|
819 | | - |
---|
820 | | - win64 = of_find_property(np, DIRECT64_PROPNAME, NULL); |
---|
821 | | - if (!win64) |
---|
822 | | - return; |
---|
823 | | - |
---|
824 | | - if (ret || win64->length < sizeof(*dwp)) |
---|
825 | | - goto delprop; |
---|
826 | | - |
---|
827 | | - dwp = win64->value; |
---|
| 791 | + dwp = win->value; |
---|
828 | 792 | liobn = (u64)be32_to_cpu(dwp->liobn); |
---|
829 | 793 | |
---|
830 | 794 | /* clear the whole window, note the arg is in kernel pages */ |
---|
.. | .. |
---|
837 | 801 | pr_debug("%pOF successfully cleared tces in window.\n", |
---|
838 | 802 | np); |
---|
839 | 803 | |
---|
840 | | - ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn); |
---|
| 804 | + ret = rtas_call(ddw_avail[DDW_REMOVE_PE_DMA_WIN], 1, 1, NULL, liobn); |
---|
841 | 805 | if (ret) |
---|
842 | 806 | pr_warn("%pOF: failed to remove direct window: rtas returned " |
---|
843 | 807 | "%d to ibm,remove-pe-dma-window(%x) %llx\n", |
---|
844 | | - np, ret, ddw_avail[2], liobn); |
---|
| 808 | + np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn); |
---|
845 | 809 | else |
---|
846 | 810 | pr_debug("%pOF: successfully removed direct window: rtas returned " |
---|
847 | 811 | "%d to ibm,remove-pe-dma-window(%x) %llx\n", |
---|
848 | | - np, ret, ddw_avail[2], liobn); |
---|
| 812 | + np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn); |
---|
| 813 | +} |
---|
849 | 814 | |
---|
850 | | -delprop: |
---|
851 | | - if (remove_prop) |
---|
852 | | - ret = of_remove_property(np, win64); |
---|
| 815 | +static void remove_ddw(struct device_node *np, bool remove_prop) |
---|
| 816 | +{ |
---|
| 817 | + struct property *win; |
---|
| 818 | + u32 ddw_avail[DDW_APPLICABLE_SIZE]; |
---|
| 819 | + int ret = 0; |
---|
| 820 | + |
---|
| 821 | + ret = of_property_read_u32_array(np, "ibm,ddw-applicable", |
---|
| 822 | + &ddw_avail[0], DDW_APPLICABLE_SIZE); |
---|
| 823 | + if (ret) |
---|
| 824 | + return; |
---|
| 825 | + |
---|
| 826 | + win = of_find_property(np, DIRECT64_PROPNAME, NULL); |
---|
| 827 | + if (!win) |
---|
| 828 | + return; |
---|
| 829 | + |
---|
| 830 | + if (win->length >= sizeof(struct dynamic_dma_window_prop)) |
---|
| 831 | + remove_dma_window(np, ddw_avail, win); |
---|
| 832 | + |
---|
| 833 | + if (!remove_prop) |
---|
| 834 | + return; |
---|
| 835 | + |
---|
| 836 | + ret = of_remove_property(np, win); |
---|
853 | 837 | if (ret) |
---|
854 | 838 | pr_warn("%pOF: failed to remove direct window property: %d\n", |
---|
855 | 839 | np, ret); |
---|
.. | .. |
---|
908 | 892 | } |
---|
909 | 893 | machine_arch_initcall(pseries, find_existing_ddw_windows); |
---|
910 | 894 | |
---|
| 895 | +/** |
---|
| 896 | + * ddw_read_ext - Get the value of an DDW extension |
---|
| 897 | + * @np: device node from which the extension value is to be read. |
---|
| 898 | + * @extnum: index number of the extension. |
---|
| 899 | + * @value: pointer to return value, modified when extension is available. |
---|
| 900 | + * |
---|
| 901 | + * Checks if "ibm,ddw-extensions" exists for this node, and get the value |
---|
| 902 | + * on index 'extnum'. |
---|
| 903 | + * It can be used only to check if a property exists, passing value == NULL. |
---|
| 904 | + * |
---|
| 905 | + * Returns: |
---|
| 906 | + * 0 if extension successfully read |
---|
| 907 | + * -EINVAL if the "ibm,ddw-extensions" does not exist, |
---|
| 908 | + * -ENODATA if "ibm,ddw-extensions" does not have a value, and |
---|
| 909 | + * -EOVERFLOW if "ibm,ddw-extensions" does not contain this extension. |
---|
| 910 | + */ |
---|
| 911 | +static inline int ddw_read_ext(const struct device_node *np, int extnum, |
---|
| 912 | + u32 *value) |
---|
| 913 | +{ |
---|
| 914 | + static const char propname[] = "ibm,ddw-extensions"; |
---|
| 915 | + u32 count; |
---|
| 916 | + int ret; |
---|
| 917 | + |
---|
| 918 | + ret = of_property_read_u32_index(np, propname, DDW_EXT_SIZE, &count); |
---|
| 919 | + if (ret) |
---|
| 920 | + return ret; |
---|
| 921 | + |
---|
| 922 | + if (count < extnum) |
---|
| 923 | + return -EOVERFLOW; |
---|
| 924 | + |
---|
| 925 | + if (!value) |
---|
| 926 | + value = &count; |
---|
| 927 | + |
---|
| 928 | + return of_property_read_u32_index(np, propname, extnum, value); |
---|
| 929 | +} |
---|
| 930 | + |
---|
911 | 931 | static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail, |
---|
912 | | - struct ddw_query_response *query) |
---|
| 932 | + struct ddw_query_response *query, |
---|
| 933 | + struct device_node *parent) |
---|
913 | 934 | { |
---|
914 | 935 | struct device_node *dn; |
---|
915 | 936 | struct pci_dn *pdn; |
---|
916 | | - u32 cfg_addr; |
---|
| 937 | + u32 cfg_addr, ext_query, query_out[5]; |
---|
917 | 938 | u64 buid; |
---|
918 | | - int ret; |
---|
| 939 | + int ret, out_sz; |
---|
| 940 | + |
---|
| 941 | + /* |
---|
| 942 | + * From LoPAR level 2.8, "ibm,ddw-extensions" index 3 can rule how many |
---|
| 943 | + * output parameters ibm,query-pe-dma-windows will have, ranging from |
---|
| 944 | + * 5 to 6. |
---|
| 945 | + */ |
---|
| 946 | + ret = ddw_read_ext(parent, DDW_EXT_QUERY_OUT_SIZE, &ext_query); |
---|
| 947 | + if (!ret && ext_query == 1) |
---|
| 948 | + out_sz = 6; |
---|
| 949 | + else |
---|
| 950 | + out_sz = 5; |
---|
919 | 951 | |
---|
920 | 952 | /* |
---|
921 | 953 | * Get the config address and phb buid of the PE window. |
---|
.. | .. |
---|
928 | 960 | buid = pdn->phb->buid; |
---|
929 | 961 | cfg_addr = ((pdn->busno << 16) | (pdn->devfn << 8)); |
---|
930 | 962 | |
---|
931 | | - ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query, |
---|
932 | | - cfg_addr, BUID_HI(buid), BUID_LO(buid)); |
---|
933 | | - dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x" |
---|
934 | | - " returned %d\n", ddw_avail[0], cfg_addr, BUID_HI(buid), |
---|
935 | | - BUID_LO(buid), ret); |
---|
| 963 | + ret = rtas_call(ddw_avail[DDW_QUERY_PE_DMA_WIN], 3, out_sz, query_out, |
---|
| 964 | + cfg_addr, BUID_HI(buid), BUID_LO(buid)); |
---|
| 965 | + dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x returned %d\n", |
---|
| 966 | + ddw_avail[DDW_QUERY_PE_DMA_WIN], cfg_addr, BUID_HI(buid), |
---|
| 967 | + BUID_LO(buid), ret); |
---|
| 968 | + |
---|
| 969 | + switch (out_sz) { |
---|
| 970 | + case 5: |
---|
| 971 | + query->windows_available = query_out[0]; |
---|
| 972 | + query->largest_available_block = query_out[1]; |
---|
| 973 | + query->page_size = query_out[2]; |
---|
| 974 | + query->migration_capable = query_out[3]; |
---|
| 975 | + break; |
---|
| 976 | + case 6: |
---|
| 977 | + query->windows_available = query_out[0]; |
---|
| 978 | + query->largest_available_block = ((u64)query_out[1] << 32) | |
---|
| 979 | + query_out[2]; |
---|
| 980 | + query->page_size = query_out[3]; |
---|
| 981 | + query->migration_capable = query_out[4]; |
---|
| 982 | + break; |
---|
| 983 | + } |
---|
| 984 | + |
---|
936 | 985 | return ret; |
---|
937 | 986 | } |
---|
938 | 987 | |
---|
.. | .. |
---|
959 | 1008 | |
---|
960 | 1009 | do { |
---|
961 | 1010 | /* extra outputs are LIOBN and dma-addr (hi, lo) */ |
---|
962 | | - ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create, |
---|
963 | | - cfg_addr, BUID_HI(buid), BUID_LO(buid), |
---|
964 | | - page_shift, window_shift); |
---|
| 1011 | + ret = rtas_call(ddw_avail[DDW_CREATE_PE_DMA_WIN], 5, 4, |
---|
| 1012 | + (u32 *)create, cfg_addr, BUID_HI(buid), |
---|
| 1013 | + BUID_LO(buid), page_shift, window_shift); |
---|
965 | 1014 | } while (rtas_busy_delay(ret)); |
---|
966 | 1015 | dev_info(&dev->dev, |
---|
967 | 1016 | "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d " |
---|
968 | | - "(liobn = 0x%x starting addr = %x %x)\n", ddw_avail[1], |
---|
969 | | - cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift, |
---|
970 | | - window_shift, ret, create->liobn, create->addr_hi, create->addr_lo); |
---|
| 1017 | + "(liobn = 0x%x starting addr = %x %x)\n", |
---|
| 1018 | + ddw_avail[DDW_CREATE_PE_DMA_WIN], cfg_addr, BUID_HI(buid), |
---|
| 1019 | + BUID_LO(buid), page_shift, window_shift, ret, create->liobn, |
---|
| 1020 | + create->addr_hi, create->addr_lo); |
---|
971 | 1021 | |
---|
972 | 1022 | return ret; |
---|
973 | 1023 | } |
---|
.. | .. |
---|
979 | 1029 | |
---|
980 | 1030 | static LIST_HEAD(failed_ddw_pdn_list); |
---|
981 | 1031 | |
---|
| 1032 | +static phys_addr_t ddw_memory_hotplug_max(void) |
---|
| 1033 | +{ |
---|
| 1034 | + phys_addr_t max_addr = memory_hotplug_max(); |
---|
| 1035 | + struct device_node *memory; |
---|
| 1036 | + |
---|
| 1037 | + for_each_node_by_type(memory, "memory") { |
---|
| 1038 | + unsigned long start, size; |
---|
| 1039 | + int n_mem_addr_cells, n_mem_size_cells, len; |
---|
| 1040 | + const __be32 *memcell_buf; |
---|
| 1041 | + |
---|
| 1042 | + memcell_buf = of_get_property(memory, "reg", &len); |
---|
| 1043 | + if (!memcell_buf || len <= 0) |
---|
| 1044 | + continue; |
---|
| 1045 | + |
---|
| 1046 | + n_mem_addr_cells = of_n_addr_cells(memory); |
---|
| 1047 | + n_mem_size_cells = of_n_size_cells(memory); |
---|
| 1048 | + |
---|
| 1049 | + start = of_read_number(memcell_buf, n_mem_addr_cells); |
---|
| 1050 | + memcell_buf += n_mem_addr_cells; |
---|
| 1051 | + size = of_read_number(memcell_buf, n_mem_size_cells); |
---|
| 1052 | + memcell_buf += n_mem_size_cells; |
---|
| 1053 | + |
---|
| 1054 | + max_addr = max_t(phys_addr_t, max_addr, start + size); |
---|
| 1055 | + } |
---|
| 1056 | + |
---|
| 1057 | + return max_addr; |
---|
| 1058 | +} |
---|
| 1059 | + |
---|
| 1060 | +/* |
---|
| 1061 | + * Platforms supporting the DDW option starting with LoPAR level 2.7 implement |
---|
| 1062 | + * ibm,ddw-extensions, which carries the rtas token for |
---|
| 1063 | + * ibm,reset-pe-dma-windows. |
---|
| 1064 | + * That rtas-call can be used to restore the default DMA window for the device. |
---|
| 1065 | + */ |
---|
| 1066 | +static void reset_dma_window(struct pci_dev *dev, struct device_node *par_dn) |
---|
| 1067 | +{ |
---|
| 1068 | + int ret; |
---|
| 1069 | + u32 cfg_addr, reset_dma_win; |
---|
| 1070 | + u64 buid; |
---|
| 1071 | + struct device_node *dn; |
---|
| 1072 | + struct pci_dn *pdn; |
---|
| 1073 | + |
---|
| 1074 | + ret = ddw_read_ext(par_dn, DDW_EXT_RESET_DMA_WIN, &reset_dma_win); |
---|
| 1075 | + if (ret) |
---|
| 1076 | + return; |
---|
| 1077 | + |
---|
| 1078 | + dn = pci_device_to_OF_node(dev); |
---|
| 1079 | + pdn = PCI_DN(dn); |
---|
| 1080 | + buid = pdn->phb->buid; |
---|
| 1081 | + cfg_addr = (pdn->busno << 16) | (pdn->devfn << 8); |
---|
| 1082 | + |
---|
| 1083 | + ret = rtas_call(reset_dma_win, 3, 1, NULL, cfg_addr, BUID_HI(buid), |
---|
| 1084 | + BUID_LO(buid)); |
---|
| 1085 | + if (ret) |
---|
| 1086 | + dev_info(&dev->dev, |
---|
| 1087 | + "ibm,reset-pe-dma-windows(%x) %x %x %x returned %d ", |
---|
| 1088 | + reset_dma_win, cfg_addr, BUID_HI(buid), BUID_LO(buid), |
---|
| 1089 | + ret); |
---|
| 1090 | +} |
---|
| 1091 | + |
---|
982 | 1092 | /* |
---|
983 | 1093 | * If the PE supports dynamic dma windows, and there is space for a table |
---|
984 | 1094 | * that can map all pages in a linear offset, then setup such a table, |
---|
.. | .. |
---|
988 | 1098 | * pdn: the parent pe node with the ibm,dma_window property |
---|
989 | 1099 | * Future: also check if we can remap the base window for our base page size |
---|
990 | 1100 | * |
---|
991 | | - * returns the dma offset for use by dma_set_mask |
---|
| 1101 | + * returns the dma offset for use by the direct mapped DMA code. |
---|
992 | 1102 | */ |
---|
993 | 1103 | static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn) |
---|
994 | 1104 | { |
---|
.. | .. |
---|
998 | 1108 | int page_shift; |
---|
999 | 1109 | u64 dma_addr, max_addr; |
---|
1000 | 1110 | struct device_node *dn; |
---|
1001 | | - u32 ddw_avail[3]; |
---|
| 1111 | + u32 ddw_avail[DDW_APPLICABLE_SIZE]; |
---|
1002 | 1112 | struct direct_window *window; |
---|
1003 | 1113 | struct property *win64; |
---|
1004 | 1114 | struct dynamic_dma_window_prop *ddwprop; |
---|
1005 | 1115 | struct failed_ddw_pdn *fpdn; |
---|
| 1116 | + bool default_win_removed = false; |
---|
1006 | 1117 | |
---|
1007 | 1118 | mutex_lock(&direct_window_init_mutex); |
---|
1008 | 1119 | |
---|
.. | .. |
---|
1031 | 1142 | * the property is actually in the parent, not the PE |
---|
1032 | 1143 | */ |
---|
1033 | 1144 | ret = of_property_read_u32_array(pdn, "ibm,ddw-applicable", |
---|
1034 | | - &ddw_avail[0], 3); |
---|
| 1145 | + &ddw_avail[0], DDW_APPLICABLE_SIZE); |
---|
1035 | 1146 | if (ret) |
---|
1036 | 1147 | goto out_failed; |
---|
1037 | 1148 | |
---|
.. | .. |
---|
1042 | 1153 | * of page sizes: supported and supported for migrate-dma. |
---|
1043 | 1154 | */ |
---|
1044 | 1155 | dn = pci_device_to_OF_node(dev); |
---|
1045 | | - ret = query_ddw(dev, ddw_avail, &query); |
---|
| 1156 | + ret = query_ddw(dev, ddw_avail, &query, pdn); |
---|
1046 | 1157 | if (ret != 0) |
---|
1047 | 1158 | goto out_failed; |
---|
1048 | 1159 | |
---|
| 1160 | + /* |
---|
| 1161 | + * If there is no window available, remove the default DMA window, |
---|
| 1162 | + * if it's present. This will make all the resources available to the |
---|
| 1163 | + * new DDW window. |
---|
| 1164 | + * If anything fails after this, we need to restore it, so also check |
---|
| 1165 | + * for extensions presence. |
---|
| 1166 | + */ |
---|
1049 | 1167 | if (query.windows_available == 0) { |
---|
1050 | | - /* |
---|
1051 | | - * no additional windows are available for this device. |
---|
1052 | | - * We might be able to reallocate the existing window, |
---|
1053 | | - * trading in for a larger page size. |
---|
1054 | | - */ |
---|
1055 | | - dev_dbg(&dev->dev, "no free dynamic windows"); |
---|
1056 | | - goto out_failed; |
---|
| 1168 | + struct property *default_win; |
---|
| 1169 | + int reset_win_ext; |
---|
| 1170 | + |
---|
| 1171 | + default_win = of_find_property(pdn, "ibm,dma-window", NULL); |
---|
| 1172 | + if (!default_win) |
---|
| 1173 | + goto out_failed; |
---|
| 1174 | + |
---|
| 1175 | + reset_win_ext = ddw_read_ext(pdn, DDW_EXT_RESET_DMA_WIN, NULL); |
---|
| 1176 | + if (reset_win_ext) |
---|
| 1177 | + goto out_failed; |
---|
| 1178 | + |
---|
| 1179 | + remove_dma_window(pdn, ddw_avail, default_win); |
---|
| 1180 | + default_win_removed = true; |
---|
| 1181 | + |
---|
| 1182 | + /* Query again, to check if the window is available */ |
---|
| 1183 | + ret = query_ddw(dev, ddw_avail, &query, pdn); |
---|
| 1184 | + if (ret != 0) |
---|
| 1185 | + goto out_failed; |
---|
| 1186 | + |
---|
| 1187 | + if (query.windows_available == 0) { |
---|
| 1188 | + /* no windows are available for this device. */ |
---|
| 1189 | + dev_dbg(&dev->dev, "no free dynamic windows"); |
---|
| 1190 | + goto out_failed; |
---|
| 1191 | + } |
---|
1057 | 1192 | } |
---|
1058 | 1193 | if (query.page_size & 4) { |
---|
1059 | 1194 | page_shift = 24; /* 16MB */ |
---|
.. | .. |
---|
1068 | 1203 | } |
---|
1069 | 1204 | /* verify the window * number of ptes will map the partition */ |
---|
1070 | 1205 | /* check largest block * page size > max memory hotplug addr */ |
---|
1071 | | - max_addr = memory_hotplug_max(); |
---|
| 1206 | + max_addr = ddw_memory_hotplug_max(); |
---|
1072 | 1207 | if (query.largest_available_block < (max_addr >> page_shift)) { |
---|
1073 | | - dev_dbg(&dev->dev, "can't map partition max 0x%llx with %u " |
---|
| 1208 | + dev_dbg(&dev->dev, "can't map partition max 0x%llx with %llu " |
---|
1074 | 1209 | "%llu-sized pages\n", max_addr, query.largest_available_block, |
---|
1075 | 1210 | 1ULL << page_shift); |
---|
1076 | 1211 | goto out_failed; |
---|
.. | .. |
---|
1144 | 1279 | kfree(win64); |
---|
1145 | 1280 | |
---|
1146 | 1281 | out_failed: |
---|
| 1282 | + if (default_win_removed) |
---|
| 1283 | + reset_dma_window(dev, pdn); |
---|
1147 | 1284 | |
---|
1148 | 1285 | fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL); |
---|
1149 | 1286 | if (!fpdn) |
---|
.. | .. |
---|
1196 | 1333 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, |
---|
1197 | 1334 | pci->table_group, dma_window); |
---|
1198 | 1335 | tbl->it_ops = &iommu_table_lpar_multi_ops; |
---|
1199 | | - iommu_init_table(tbl, pci->phb->node); |
---|
| 1336 | + iommu_init_table(tbl, pci->phb->node, 0, 0); |
---|
1200 | 1337 | iommu_register_group(pci->table_group, |
---|
1201 | 1338 | pci_domain_nr(pci->phb->bus), 0); |
---|
1202 | 1339 | pr_debug(" created table: %p\n", pci->table_group); |
---|
.. | .. |
---|
1205 | 1342 | } |
---|
1206 | 1343 | |
---|
1207 | 1344 | set_iommu_table_base(&dev->dev, pci->table_group->tables[0]); |
---|
1208 | | - iommu_add_device(&dev->dev); |
---|
| 1345 | + iommu_add_device(pci->table_group, &dev->dev); |
---|
1209 | 1346 | } |
---|
1210 | 1347 | |
---|
1211 | | -static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) |
---|
| 1348 | +static bool iommu_bypass_supported_pSeriesLP(struct pci_dev *pdev, u64 dma_mask) |
---|
1212 | 1349 | { |
---|
1213 | | - bool ddw_enabled = false; |
---|
1214 | | - struct device_node *pdn, *dn; |
---|
1215 | | - struct pci_dev *pdev; |
---|
| 1350 | + struct device_node *dn = pci_device_to_OF_node(pdev), *pdn; |
---|
1216 | 1351 | const __be32 *dma_window = NULL; |
---|
1217 | | - u64 dma_offset; |
---|
1218 | | - |
---|
1219 | | - if (!dev->dma_mask) |
---|
1220 | | - return -EIO; |
---|
1221 | | - |
---|
1222 | | - if (!dev_is_pci(dev)) |
---|
1223 | | - goto check_mask; |
---|
1224 | | - |
---|
1225 | | - pdev = to_pci_dev(dev); |
---|
1226 | 1352 | |
---|
1227 | 1353 | /* only attempt to use a new window if 64-bit DMA is requested */ |
---|
1228 | | - if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) { |
---|
1229 | | - dn = pci_device_to_OF_node(pdev); |
---|
1230 | | - dev_dbg(dev, "node is %pOF\n", dn); |
---|
| 1354 | + if (dma_mask < DMA_BIT_MASK(64)) |
---|
| 1355 | + return false; |
---|
1231 | 1356 | |
---|
1232 | | - /* |
---|
1233 | | - * the device tree might contain the dma-window properties |
---|
1234 | | - * per-device and not necessarily for the bus. So we need to |
---|
1235 | | - * search upwards in the tree until we either hit a dma-window |
---|
1236 | | - * property, OR find a parent with a table already allocated. |
---|
1237 | | - */ |
---|
1238 | | - for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group; |
---|
1239 | | - pdn = pdn->parent) { |
---|
1240 | | - dma_window = of_get_property(pdn, "ibm,dma-window", NULL); |
---|
1241 | | - if (dma_window) |
---|
1242 | | - break; |
---|
1243 | | - } |
---|
1244 | | - if (pdn && PCI_DN(pdn)) { |
---|
1245 | | - dma_offset = enable_ddw(pdev, pdn); |
---|
1246 | | - if (dma_offset != 0) { |
---|
1247 | | - dev_info(dev, "Using 64-bit direct DMA at offset %llx\n", dma_offset); |
---|
1248 | | - set_dma_offset(dev, dma_offset); |
---|
1249 | | - set_dma_ops(dev, &dma_nommu_ops); |
---|
1250 | | - ddw_enabled = true; |
---|
1251 | | - } |
---|
1252 | | - } |
---|
| 1357 | + dev_dbg(&pdev->dev, "node is %pOF\n", dn); |
---|
| 1358 | + |
---|
| 1359 | + /* |
---|
| 1360 | + * the device tree might contain the dma-window properties |
---|
| 1361 | + * per-device and not necessarily for the bus. So we need to |
---|
| 1362 | + * search upwards in the tree until we either hit a dma-window |
---|
| 1363 | + * property, OR find a parent with a table already allocated. |
---|
| 1364 | + */ |
---|
| 1365 | + for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->table_group; |
---|
| 1366 | + pdn = pdn->parent) { |
---|
| 1367 | + dma_window = of_get_property(pdn, "ibm,dma-window", NULL); |
---|
| 1368 | + if (dma_window) |
---|
| 1369 | + break; |
---|
1253 | 1370 | } |
---|
1254 | 1371 | |
---|
1255 | | - /* fall back on iommu ops */ |
---|
1256 | | - if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) { |
---|
1257 | | - dev_info(dev, "Restoring 32-bit DMA via iommu\n"); |
---|
1258 | | - set_dma_ops(dev, &dma_iommu_ops); |
---|
| 1372 | + if (pdn && PCI_DN(pdn)) { |
---|
| 1373 | + pdev->dev.archdata.dma_offset = enable_ddw(pdev, pdn); |
---|
| 1374 | + if (pdev->dev.archdata.dma_offset) |
---|
| 1375 | + return true; |
---|
1259 | 1376 | } |
---|
1260 | 1377 | |
---|
1261 | | -check_mask: |
---|
1262 | | - if (!dma_supported(dev, dma_mask)) |
---|
1263 | | - return -EIO; |
---|
1264 | | - |
---|
1265 | | - *dev->dma_mask = dma_mask; |
---|
1266 | | - return 0; |
---|
1267 | | -} |
---|
1268 | | - |
---|
1269 | | -static u64 dma_get_required_mask_pSeriesLP(struct device *dev) |
---|
1270 | | -{ |
---|
1271 | | - if (!dev->dma_mask) |
---|
1272 | | - return 0; |
---|
1273 | | - |
---|
1274 | | - if (!disable_ddw && dev_is_pci(dev)) { |
---|
1275 | | - struct pci_dev *pdev = to_pci_dev(dev); |
---|
1276 | | - struct device_node *dn; |
---|
1277 | | - |
---|
1278 | | - dn = pci_device_to_OF_node(pdev); |
---|
1279 | | - |
---|
1280 | | - /* search upwards for ibm,dma-window */ |
---|
1281 | | - for (; dn && PCI_DN(dn) && !PCI_DN(dn)->table_group; |
---|
1282 | | - dn = dn->parent) |
---|
1283 | | - if (of_get_property(dn, "ibm,dma-window", NULL)) |
---|
1284 | | - break; |
---|
1285 | | - /* if there is a ibm,ddw-applicable property require 64 bits */ |
---|
1286 | | - if (dn && PCI_DN(dn) && |
---|
1287 | | - of_get_property(dn, "ibm,ddw-applicable", NULL)) |
---|
1288 | | - return DMA_BIT_MASK(64); |
---|
1289 | | - } |
---|
1290 | | - |
---|
1291 | | - return dma_iommu_ops.get_required_mask(dev); |
---|
| 1378 | + return false; |
---|
1292 | 1379 | } |
---|
1293 | 1380 | |
---|
1294 | 1381 | static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, |
---|
.. | .. |
---|
1383 | 1470 | if (firmware_has_feature(FW_FEATURE_LPAR)) { |
---|
1384 | 1471 | pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeriesLP; |
---|
1385 | 1472 | pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeriesLP; |
---|
1386 | | - ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; |
---|
1387 | | - ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP; |
---|
| 1473 | + if (!disable_ddw) |
---|
| 1474 | + pseries_pci_controller_ops.iommu_bypass_supported = |
---|
| 1475 | + iommu_bypass_supported_pSeriesLP; |
---|
1388 | 1476 | } else { |
---|
1389 | 1477 | pseries_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pSeries; |
---|
1390 | 1478 | pseries_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pSeries; |
---|
.. | .. |
---|
1401 | 1489 | { |
---|
1402 | 1490 | if (strcmp(str, "off") == 0 && |
---|
1403 | 1491 | firmware_has_feature(FW_FEATURE_LPAR) && |
---|
1404 | | - firmware_has_feature(FW_FEATURE_MULTITCE)) { |
---|
| 1492 | + (firmware_has_feature(FW_FEATURE_PUT_TCE_IND) || |
---|
| 1493 | + firmware_has_feature(FW_FEATURE_STUFF_TCE))) { |
---|
1405 | 1494 | printk(KERN_INFO "Disabling MULTITCE firmware feature\n"); |
---|
1406 | | - powerpc_firmware_features &= ~FW_FEATURE_MULTITCE; |
---|
| 1495 | + powerpc_firmware_features &= |
---|
| 1496 | + ~(FW_FEATURE_PUT_TCE_IND | FW_FEATURE_STUFF_TCE); |
---|
1407 | 1497 | } |
---|
1408 | 1498 | return 1; |
---|
1409 | 1499 | } |
---|
1410 | 1500 | |
---|
1411 | 1501 | __setup("multitce=", disable_multitce); |
---|
1412 | 1502 | |
---|
| 1503 | +static int tce_iommu_bus_notifier(struct notifier_block *nb, |
---|
| 1504 | + unsigned long action, void *data) |
---|
| 1505 | +{ |
---|
| 1506 | + struct device *dev = data; |
---|
| 1507 | + |
---|
| 1508 | + switch (action) { |
---|
| 1509 | + case BUS_NOTIFY_DEL_DEVICE: |
---|
| 1510 | + iommu_del_device(dev); |
---|
| 1511 | + return 0; |
---|
| 1512 | + default: |
---|
| 1513 | + return 0; |
---|
| 1514 | + } |
---|
| 1515 | +} |
---|
| 1516 | + |
---|
| 1517 | +static struct notifier_block tce_iommu_bus_nb = { |
---|
| 1518 | + .notifier_call = tce_iommu_bus_notifier, |
---|
| 1519 | +}; |
---|
| 1520 | + |
---|
| 1521 | +static int __init tce_iommu_bus_notifier_init(void) |
---|
| 1522 | +{ |
---|
| 1523 | + bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb); |
---|
| 1524 | + return 0; |
---|
| 1525 | +} |
---|
1413 | 1526 | machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init); |
---|