Skip to content

Commit 1211ee6

Browse files
ldu4mpe
authored andcommitted
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: ba2dd8a ("powerpc/pseries/mm: call H_BLOCK_REMOVE") Signed-off-by: Laurent Dufour <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 3a83f67 commit 1211ee6

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

arch/powerpc/platforms/pseries/lpar.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ EXPORT_SYMBOL(plpar_hcall);
5656
EXPORT_SYMBOL(plpar_hcall9);
5757
EXPORT_SYMBOL(plpar_hcall_norets);
5858

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+
5968
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
6069
static u8 dtl_mask = DTL_LOG_PREEMPT;
6170
#else
@@ -1311,6 +1320,137 @@ static void do_block_remove(unsigned long number, struct ppc64_tlb_batch *batch,
13111320
(void)call_block_remove(pix, param, true);
13121321
}
13131322

1323+
/*
1324+
* TLB Block Invalidate Characteristics
1325+
*
1326+
* These characteristics define the size of the block the hcall H_BLOCK_REMOVE
1327+
* is able to process for each couple segment base page size, actual page size.
1328+
*
1329+
* The ibm,get-system-parameter properties is returning a buffer with the
1330+
* following layout:
1331+
*
1332+
* [ 2 bytes size of the RTAS buffer (excluding these 2 bytes) ]
1333+
* -----------------
1334+
* TLB Block Invalidate Specifiers:
1335+
* [ 1 byte LOG base 2 of the TLB invalidate block size being specified ]
1336+
* [ 1 byte Number of page sizes (N) that are supported for the specified
1337+
* TLB invalidate block size ]
1338+
* [ 1 byte Encoded segment base page size and actual page size
1339+
* MSB=0 means 4k segment base page size and actual page size
1340+
* MSB=1 the penc value in mmu_psize_def ]
1341+
* ...
1342+
* -----------------
1343+
* Next TLB Block Invalidate Specifiers...
1344+
* -----------------
1345+
* [ 0 ]
1346+
*/
1347+
static inline void set_hblkrm_bloc_size(int bpsize, int psize,
1348+
unsigned int block_size)
1349+
{
1350+
if (block_size > hblkrm_size[bpsize][psize])
1351+
hblkrm_size[bpsize][psize] = block_size;
1352+
}
1353+
1354+
/*
1355+
* Decode the Encoded segment base page size and actual page size.
1356+
* PAPR specifies:
1357+
* - bit 7 is the L bit
1358+
* - bits 0-5 are the penc value
1359+
* If the L bit is 0, this means 4K segment base page size and actual page size
1360+
* otherwise the penc value should be read.
1361+
*/
1362+
#define HBLKRM_L_MASK 0x80
1363+
#define HBLKRM_PENC_MASK 0x3f
1364+
static inline void __init check_lp_set_hblkrm(unsigned int lp,
1365+
unsigned int block_size)
1366+
{
1367+
unsigned int bpsize, psize;
1368+
1369+
/* First, check the L bit, if not set, this means 4K */
1370+
if ((lp & HBLKRM_L_MASK) == 0) {
1371+
set_hblkrm_bloc_size(MMU_PAGE_4K, MMU_PAGE_4K, block_size);
1372+
return;
1373+
}
1374+
1375+
lp &= HBLKRM_PENC_MASK;
1376+
for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++) {
1377+
struct mmu_psize_def *def = &mmu_psize_defs[bpsize];
1378+
1379+
for (psize = 0; psize < MMU_PAGE_COUNT; psize++) {
1380+
if (def->penc[psize] == lp) {
1381+
set_hblkrm_bloc_size(bpsize, psize, block_size);
1382+
return;
1383+
}
1384+
}
1385+
}
1386+
}
1387+
1388+
#define SPLPAR_TLB_BIC_TOKEN 50
1389+
1390+
/*
1391+
* The size of the TLB Block Invalidate Characteristics is variable. But at the
1392+
* maximum it will be the number of possible page sizes *2 + 10 bytes.
1393+
* Currently MMU_PAGE_COUNT is 16, which means 42 bytes. Use a cache line size
1394+
* (128 bytes) for the buffer to get plenty of space.
1395+
*/
1396+
#define SPLPAR_TLB_BIC_MAXLENGTH 128
1397+
1398+
void __init pseries_lpar_read_hblkrm_characteristics(void)
1399+
{
1400+
unsigned char local_buffer[SPLPAR_TLB_BIC_MAXLENGTH];
1401+
int call_status, len, idx, bpsize;
1402+
1403+
spin_lock(&rtas_data_buf_lock);
1404+
memset(rtas_data_buf, 0, RTAS_DATA_BUF_SIZE);
1405+
call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1,
1406+
NULL,
1407+
SPLPAR_TLB_BIC_TOKEN,
1408+
__pa(rtas_data_buf),
1409+
RTAS_DATA_BUF_SIZE);
1410+
memcpy(local_buffer, rtas_data_buf, SPLPAR_TLB_BIC_MAXLENGTH);
1411+
local_buffer[SPLPAR_TLB_BIC_MAXLENGTH - 1] = '\0';
1412+
spin_unlock(&rtas_data_buf_lock);
1413+
1414+
if (call_status != 0) {
1415+
pr_warn("%s %s Error calling get-system-parameter (0x%x)\n",
1416+
__FILE__, __func__, call_status);
1417+
return;
1418+
}
1419+
1420+
/*
1421+
* The first two (2) bytes of the data in the buffer are the length of
1422+
* the returned data, not counting these first two (2) bytes.
1423+
*/
1424+
len = be16_to_cpu(*((u16 *)local_buffer)) + 2;
1425+
if (len > SPLPAR_TLB_BIC_MAXLENGTH) {
1426+
pr_warn("%s too large returned buffer %d", __func__, len);
1427+
return;
1428+
}
1429+
1430+
idx = 2;
1431+
while (idx < len) {
1432+
u8 block_shift = local_buffer[idx++];
1433+
u32 block_size;
1434+
unsigned int npsize;
1435+
1436+
if (!block_shift)
1437+
break;
1438+
1439+
block_size = 1 << block_shift;
1440+
1441+
for (npsize = local_buffer[idx++];
1442+
npsize > 0 && idx < len; npsize--)
1443+
check_lp_set_hblkrm((unsigned int) local_buffer[idx++],
1444+
block_size);
1445+
}
1446+
1447+
for (bpsize = 0; bpsize < MMU_PAGE_COUNT; bpsize++)
1448+
for (idx = 0; idx < MMU_PAGE_COUNT; idx++)
1449+
if (hblkrm_size[bpsize][idx])
1450+
pr_info("H_BLOCK_REMOVE supports base psize:%d psize:%d block size:%d",
1451+
bpsize, idx, hblkrm_size[bpsize][idx]);
1452+
}
1453+
13141454
/*
13151455
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
13161456
* lock.

arch/powerpc/platforms/pseries/pseries.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,6 @@ static inline unsigned long cmo_get_page_size(void)
112112
int dlpar_workqueue_init(void);
113113

114114
void pseries_setup_rfi_flush(void);
115+
void pseries_lpar_read_hblkrm_characteristics(void);
115116

116117
#endif /* _PSERIES_PSERIES_H */

arch/powerpc/platforms/pseries/setup.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ static void __init pSeries_setup_arch(void)
744744

745745
pseries_setup_rfi_flush();
746746
setup_stf_barrier();
747+
pseries_lpar_read_hblkrm_characteristics();
747748

748749
/* By default, only probe PCI (can be overridden by rtas_pci) */
749750
pci_add_flags(PCI_PROBE_ONLY);

0 commit comments

Comments
 (0)