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

powerpc/pseries/iommu: Replace hard-coded page shift

Some functions assume IOMMU page size can only be 4K (pageshift == 12).
Update them to accept any page size passed, so we can use 64K pages.

In the process, some defines like TCE_SHIFT were made obsolete, and then
removed.

IODA3 Revision 3.0_prd1 (OpenPowerFoundation), Figures 3.4 and 3.5 show
a RPN of 52-bit, and considers a 12-bit pageshift, so there should be
no need of using TCE_RPN_MASK, which masks out any bit after 40 in rpn.
It's usage removed from tce_build_pSeries(), tce_build_pSeriesLP(), and
tce_buildmulti_pSeriesLP().

Most places had a tbl struct, so using tbl->it_page_shift was simple.
tce_free_pSeriesLP() was a special case, since callers not always have a
tbl struct, so adding a tceshift parameter seems the right thing to do.

Signed-off-by: Leonardo Bras <leobras.c@gmail.com>
Reviewed-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Reviewed-by: Frederic Barrat <fbarrat@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210817063929.38701-2-leobras.c@gmail.com

authored by

Leonardo Bras and committed by
Michael Ellerman
0c634baf 9a245d0e

+23 -24
-8
arch/powerpc/include/asm/tce.h
··· 19 19 #define TCE_VB 0 20 20 #define TCE_PCI 1 21 21 22 - /* TCE page size is 4096 bytes (1 << 12) */ 23 - 24 - #define TCE_SHIFT 12 25 - #define TCE_PAGE_SIZE (1 << TCE_SHIFT) 26 - 27 22 #define TCE_ENTRY_SIZE 8 /* each TCE is 64 bits */ 28 - 29 - #define TCE_RPN_MASK 0xfffffffffful /* 40-bit RPN (4K pages) */ 30 - #define TCE_RPN_SHIFT 12 31 23 #define TCE_VALID 0x800 /* TCE valid */ 32 24 #define TCE_ALLIO 0x400 /* TCE valid for all lpars */ 33 25 #define TCE_PCI_WRITE 0x2 /* write from PCI allowed */
+23 -16
arch/powerpc/platforms/pseries/iommu.c
··· 107 107 u64 proto_tce; 108 108 __be64 *tcep; 109 109 u64 rpn; 110 + const unsigned long tceshift = tbl->it_page_shift; 111 + const unsigned long pagesize = IOMMU_PAGE_SIZE(tbl); 110 112 111 113 proto_tce = TCE_PCI_READ; // Read allowed 112 114 ··· 119 117 120 118 while (npages--) { 121 119 /* can't move this out since we might cross MEMBLOCK boundary */ 122 - rpn = __pa(uaddr) >> TCE_SHIFT; 123 - *tcep = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT); 120 + rpn = __pa(uaddr) >> tceshift; 121 + *tcep = cpu_to_be64(proto_tce | rpn << tceshift); 124 122 125 - uaddr += TCE_PAGE_SIZE; 123 + uaddr += pagesize; 126 124 tcep++; 127 125 } 128 126 return 0; ··· 148 146 return be64_to_cpu(*tcep); 149 147 } 150 148 151 - static void tce_free_pSeriesLP(unsigned long liobn, long, long); 149 + static void tce_free_pSeriesLP(unsigned long liobn, long, long, long); 152 150 static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long); 153 151 154 152 static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, ··· 168 166 proto_tce |= TCE_PCI_WRITE; 169 167 170 168 while (npages--) { 171 - tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift; 169 + tce = proto_tce | rpn << tceshift; 172 170 rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce); 173 171 174 172 if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) { 175 173 ret = (int)rc; 176 - tce_free_pSeriesLP(liobn, tcenum_start, 174 + tce_free_pSeriesLP(liobn, tcenum_start, tceshift, 177 175 (npages_start - (npages + 1))); 178 176 break; 179 177 } ··· 207 205 long tcenum_start = tcenum, npages_start = npages; 208 206 int ret = 0; 209 207 unsigned long flags; 208 + const unsigned long tceshift = tbl->it_page_shift; 210 209 211 210 if ((npages == 1) || !firmware_has_feature(FW_FEATURE_PUT_TCE_IND)) { 212 211 return tce_build_pSeriesLP(tbl->it_index, tcenum, 213 - tbl->it_page_shift, npages, uaddr, 212 + tceshift, npages, uaddr, 214 213 direction, attrs); 215 214 } 216 215 ··· 228 225 if (!tcep) { 229 226 local_irq_restore(flags); 230 227 return tce_build_pSeriesLP(tbl->it_index, tcenum, 231 - tbl->it_page_shift, 228 + tceshift, 232 229 npages, uaddr, direction, attrs); 233 230 } 234 231 __this_cpu_write(tce_page, tcep); 235 232 } 236 233 237 - rpn = __pa(uaddr) >> TCE_SHIFT; 234 + rpn = __pa(uaddr) >> tceshift; 238 235 proto_tce = TCE_PCI_READ; 239 236 if (direction != DMA_TO_DEVICE) 240 237 proto_tce |= TCE_PCI_WRITE; ··· 248 245 limit = min_t(long, npages, 4096/TCE_ENTRY_SIZE); 249 246 250 247 for (l = 0; l < limit; l++) { 251 - tcep[l] = cpu_to_be64(proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT); 248 + tcep[l] = cpu_to_be64(proto_tce | rpn << tceshift); 252 249 rpn++; 253 250 } 254 251 255 252 rc = plpar_tce_put_indirect((u64)tbl->it_index, 256 - (u64)tcenum << 12, 253 + (u64)tcenum << tceshift, 257 254 (u64)__pa(tcep), 258 255 limit); 259 256 ··· 280 277 return ret; 281 278 } 282 279 283 - static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages) 280 + static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long tceshift, 281 + long npages) 284 282 { 285 283 u64 rc; 286 284 287 285 while (npages--) { 288 - rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0); 286 + rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, 0); 289 287 290 288 if (rc && printk_ratelimit()) { 291 289 printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc); ··· 305 301 u64 rc; 306 302 307 303 if (!firmware_has_feature(FW_FEATURE_STUFF_TCE)) 308 - return tce_free_pSeriesLP(tbl->it_index, tcenum, npages); 304 + return tce_free_pSeriesLP(tbl->it_index, tcenum, 305 + tbl->it_page_shift, npages); 309 306 310 - rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages); 307 + rc = plpar_tce_stuff((u64)tbl->it_index, 308 + (u64)tcenum << tbl->it_page_shift, 0, npages); 311 309 312 310 if (rc && printk_ratelimit()) { 313 311 printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n"); ··· 325 319 u64 rc; 326 320 unsigned long tce_ret; 327 321 328 - rc = plpar_tce_get((u64)tbl->it_index, (u64)tcenum << 12, &tce_ret); 322 + rc = plpar_tce_get((u64)tbl->it_index, 323 + (u64)tcenum << tbl->it_page_shift, &tce_ret); 329 324 330 325 if (rc && printk_ratelimit()) { 331 326 printk("tce_get_pSeriesLP: plpar_tce_get failed. rc=%lld\n", rc);