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

powerpc/pseries: Read TLB Block Invalidate Characteristics

The PAPR document specifies the TLB Block Invalidate Characteristics
which tells for each pair of segment base page size, actual page size,
the size of the block the hcall H_BLOCK_REMOVE supports.

These characteristics are loaded at boot time in a new table
hblkr_size. The table is separate from the mmu_psize_def because this
is specific to the pseries platform.

A new init function, pseries_lpar_read_hblkrm_characteristics() is
added to read the characteristics. It is called from
pSeries_setup_arch().

Fixes: ba2dd8a26baa ("powerpc/pseries/mm: call H_BLOCK_REMOVE")
Signed-off-by: Laurent Dufour <ldufour@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20190920130523.20441-2-ldufour@linux.ibm.com

authored by

Laurent Dufour and committed by
Michael Ellerman
1211ee61 3a83f677

+142
+140
arch/powerpc/platforms/pseries/lpar.c
··· 56 56 EXPORT_SYMBOL(plpar_hcall9); 57 57 EXPORT_SYMBOL(plpar_hcall_norets); 58 58 59 + /* 60 + * H_BLOCK_REMOVE supported block size for this page size in segment who's base 61 + * page size is that page size. 62 + * 63 + * The first index is the segment base page size, the second one is the actual 64 + * page size. 65 + */ 66 + static int hblkrm_size[MMU_PAGE_COUNT][MMU_PAGE_COUNT] __ro_after_init; 67 + 59 68 #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE 60 69 static u8 dtl_mask = DTL_LOG_PREEMPT; 61 70 #else ··· 1318 1309 1319 1310 if (pix) 1320 1311 (void)call_block_remove(pix, param, true); 1312 + } 1313 + 1314 + /* 1315 + * TLB Block Invalidate Characteristics 1316 + * 1317 + * These characteristics define the size of the block the hcall H_BLOCK_REMOVE 1318 + * is able to process for each couple segment base page size, actual page size. 1319 + * 1320 + * The ibm,get-system-parameter properties is returning a buffer with the 1321 + * following layout: 1322 + * 1323 + * [ 2 bytes size of the RTAS buffer (excluding these 2 bytes) ] 1324 + * ----------------- 1325 + * TLB Block Invalidate Specifiers: 1326 + * [ 1 byte LOG base 2 of the TLB invalidate block size being specified ] 1327 + * [ 1 byte Number of page sizes (N) that are supported for the specified 1328 + * TLB invalidate block size ] 1329 + * [ 1 byte Encoded segment base page size and actual page size 1330 + * MSB=0 means 4k segment base page size and actual page size 1331 + * MSB=1 the penc value in mmu_psize_def ] 1332 + * ... 1333 + * ----------------- 1334 + * Next TLB Block Invalidate Specifiers... 1335 + * ----------------- 1336 + * [ 0 ] 1337 + */ 1338 + static inline void set_hblkrm_bloc_size(int bpsize, int psize, 1339 + unsigned int block_size) 1340 + { 1341 + if (block_size > hblkrm_size[bpsize][psize]) 1342 + hblkrm_size[bpsize][psize] = block_size; 1343 + } 1344 + 1345 + /* 1346 + * Decode the Encoded segment base page size and actual page size. 1347 + * PAPR specifies: 1348 + * - bit 7 is the L bit 1349 + * - bits 0-5 are the penc value 1350 + * If the L bit is 0, this means 4K segment base page size and actual page size 1351 + * otherwise the penc value should be read. 1352 + */ 1353 + #define HBLKRM_L_MASK 0x80 1354 + #define HBLKRM_PENC_MASK 0x3f 1355 + static inline void __init check_lp_set_hblkrm(unsigned int lp, 1356 + unsigned int block_size) 1357 + { 1358 + unsigned int bpsize, psize; 1359 + 1360 + /* First, check the L bit, if not set, this means 4K */ 1361 + if ((lp & HBLKRM_L_MASK) == 0) { 1362 + set_hblkrm_bloc_size(MMU_PAGE_4K, MMU_PAGE_4K, block_size); 1363 + return; 1364 + } 1365 + 1366 + lp &= HBLKRM_PENC_MASK; 1367 + for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++) { 1368 + struct mmu_psize_def *def = &mmu_psize_defs[bpsize]; 1369 + 1370 + for (psize = 0; psize < MMU_PAGE_COUNT; psize++) { 1371 + if (def->penc[psize] == lp) { 1372 + set_hblkrm_bloc_size(bpsize, psize, block_size); 1373 + return; 1374 + } 1375 + } 1376 + } 1377 + } 1378 + 1379 + #define SPLPAR_TLB_BIC_TOKEN 50 1380 + 1381 + /* 1382 + * The size of the TLB Block Invalidate Characteristics is variable. But at the 1383 + * maximum it will be the number of possible page sizes *2 + 10 bytes. 1384 + * Currently MMU_PAGE_COUNT is 16, which means 42 bytes. Use a cache line size 1385 + * (128 bytes) for the buffer to get plenty of space. 1386 + */ 1387 + #define SPLPAR_TLB_BIC_MAXLENGTH 128 1388 + 1389 + void __init pseries_lpar_read_hblkrm_characteristics(void) 1390 + { 1391 + unsigned char local_buffer[SPLPAR_TLB_BIC_MAXLENGTH]; 1392 + int call_status, len, idx, bpsize; 1393 + 1394 + spin_lock(&rtas_data_buf_lock); 1395 + memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE); 1396 + call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, 1397 + NULL, 1398 + SPLPAR_TLB_BIC_TOKEN, 1399 + __pa(rtas_data_buf), 1400 + RTAS_DATA_BUF_SIZE); 1401 + memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH); 1402 + local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0'; 1403 + spin_unlock(&rtas_data_buf_lock); 1404 + 1405 + if (call_status != 0) { 1406 + pr_warn("%s %s Error calling get-system-parameter (0x%x)\n", 1407 + __FILE__, __func__, call_status); 1408 + return; 1409 + } 1410 + 1411 + /* 1412 + * The first two (2) bytes of the data in the buffer are the length of 1413 + * the returned data, not counting these first two (2) bytes. 1414 + */ 1415 + len = be16_to_cpu(*((u16 *)local_buffer)) + 2; 1416 + if (len > SPLPAR_TLB_BIC_MAXLENGTH) { 1417 + pr_warn("%s too large returned buffer %d", __func__, len); 1418 + return; 1419 + } 1420 + 1421 + idx = 2; 1422 + while (idx < len) { 1423 + u8 block_shift = local_buffer[idx++]; 1424 + u32 block_size; 1425 + unsigned int npsize; 1426 + 1427 + if (!block_shift) 1428 + break; 1429 + 1430 + block_size = 1 << block_shift; 1431 + 1432 + for (npsize = local_buffer[idx++]; 1433 + npsize > 0 && idx < len; npsize--) 1434 + check_lp_set_hblkrm((unsigned int) local_buffer[idx++], 1435 + block_size); 1436 + } 1437 + 1438 + for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++) 1439 + for (idx = 0; idx < MMU_PAGE_COUNT; idx++) 1440 + if (hblkrm_size[bpsize][idx]) 1441 + pr_info("H_BLOCK_REMOVE supports base psize:%d psize:%d block size:%d", 1442 + bpsize, idx, hblkrm_size[bpsize][idx]); 1321 1443 } 1322 1444 1323 1445 /*
+1
arch/powerpc/platforms/pseries/pseries.h
··· 112 112 int dlpar_workqueue_init(void); 113 113 114 114 void pseries_setup_rfi_flush(void); 115 + void pseries_lpar_read_hblkrm_characteristics(void); 115 116 116 117 #endif /* _PSERIES_PSERIES_H */
+1
arch/powerpc/platforms/pseries/setup.c
··· 744 744 745 745 pseries_setup_rfi_flush(); 746 746 setup_stf_barrier(); 747 + pseries_lpar_read_hblkrm_characteristics(); 747 748 748 749 /* By default, only probe PCI (can be overridden by rtas_pci) */ 749 750 pci_add_flags(PCI_PROBE_ONLY);