Skip to content

Commit d5df9dc

Browse files
author
Marc Zyngier
committed
irqchip/gic-v3-its: Probe ITS page size for all GITS_BASERn registers
The GICv3 ITS driver assumes that once it has latched on a page size for a given BASER register, it can use the same page size as the maximum page size for all subsequent BASER registers. Although it worked so far, nothing in the architecture guarantees this, and Nianyao Tang hit this problem on some undisclosed implementation. Let's bite the bullet and probe the the supported page size on all BASER registers before starting to populate the tables. This simplifies the setup a bit, at the expense of a few additional MMIO accesses. Signed-off-by: Marc Zyngier <[email protected]> Reported-by: Nianyao Tang <[email protected]> Tested-by: Nianyao Tang <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bd59b34 commit d5df9dc

File tree

1 file changed

+66
-34
lines changed

1 file changed

+66
-34
lines changed

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,18 +2036,17 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser,
20362036
}
20372037

20382038
static int its_setup_baser(struct its_node *its, struct its_baser *baser,
2039-
u64 cache, u64 shr, u32 psz, u32 order,
2040-
bool indirect)
2039+
u64 cache, u64 shr, u32 order, bool indirect)
20412040
{
20422041
u64 val = its_read_baser(its, baser);
20432042
u64 esz = GITS_BASER_ENTRY_SIZE(val);
20442043
u64 type = GITS_BASER_TYPE(val);
20452044
u64 baser_phys, tmp;
2046-
u32 alloc_pages;
2045+
u32 alloc_pages, psz;
20472046
struct page *page;
20482047
void *base;
20492048

2050-
retry_alloc_baser:
2049+
psz = baser->psz;
20512050
alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz);
20522051
if (alloc_pages > GITS_BASER_PAGES_MAX) {
20532052
pr_warn("ITS@%pa: %s too large, reduce ITS pages %u->%u\n",
@@ -2120,25 +2119,6 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
21202119
goto retry_baser;
21212120
}
21222121

2123-
if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) {
2124-
/*
2125-
* Page size didn't stick. Let's try a smaller
2126-
* size and retry. If we reach 4K, then
2127-
* something is horribly wrong...
2128-
*/
2129-
free_pages((unsigned long)base, order);
2130-
baser->base = NULL;
2131-
2132-
switch (psz) {
2133-
case SZ_16K:
2134-
psz = SZ_4K;
2135-
goto retry_alloc_baser;
2136-
case SZ_64K:
2137-
psz = SZ_16K;
2138-
goto retry_alloc_baser;
2139-
}
2140-
}
2141-
21422122
if (val != tmp) {
21432123
pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
21442124
&its->phys_base, its_base_type_string[type],
@@ -2164,13 +2144,14 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser,
21642144

21652145
static bool its_parse_indirect_baser(struct its_node *its,
21662146
struct its_baser *baser,
2167-
u32 psz, u32 *order, u32 ids)
2147+
u32 *order, u32 ids)
21682148
{
21692149
u64 tmp = its_read_baser(its, baser);
21702150
u64 type = GITS_BASER_TYPE(tmp);
21712151
u64 esz = GITS_BASER_ENTRY_SIZE(tmp);
21722152
u64 val = GITS_BASER_InnerShareable | GITS_BASER_RaWaWb;
21732153
u32 new_order = *order;
2154+
u32 psz = baser->psz;
21742155
bool indirect = false;
21752156

21762157
/* No need to enable Indirection if memory requirement < (psz*2)bytes */
@@ -2288,11 +2269,58 @@ static void its_free_tables(struct its_node *its)
22882269
}
22892270
}
22902271

2272+
static int its_probe_baser_psz(struct its_node *its, struct its_baser *baser)
2273+
{
2274+
u64 psz = SZ_64K;
2275+
2276+
while (psz) {
2277+
u64 val, gpsz;
2278+
2279+
val = its_read_baser(its, baser);
2280+
val &= ~GITS_BASER_PAGE_SIZE_MASK;
2281+
2282+
switch (psz) {
2283+
case SZ_64K:
2284+
gpsz = GITS_BASER_PAGE_SIZE_64K;
2285+
break;
2286+
case SZ_16K:
2287+
gpsz = GITS_BASER_PAGE_SIZE_16K;
2288+
break;
2289+
case SZ_4K:
2290+
default:
2291+
gpsz = GITS_BASER_PAGE_SIZE_4K;
2292+
break;
2293+
}
2294+
2295+
gpsz >>= GITS_BASER_PAGE_SIZE_SHIFT;
2296+
2297+
val |= FIELD_PREP(GITS_BASER_PAGE_SIZE_MASK, gpsz);
2298+
its_write_baser(its, baser, val);
2299+
2300+
if (FIELD_GET(GITS_BASER_PAGE_SIZE_MASK, baser->val) == gpsz)
2301+
break;
2302+
2303+
switch (psz) {
2304+
case SZ_64K:
2305+
psz = SZ_16K;
2306+
break;
2307+
case SZ_16K:
2308+
psz = SZ_4K;
2309+
break;
2310+
case SZ_4K:
2311+
default:
2312+
return -1;
2313+
}
2314+
}
2315+
2316+
baser->psz = psz;
2317+
return 0;
2318+
}
2319+
22912320
static int its_alloc_tables(struct its_node *its)
22922321
{
22932322
u64 shr = GITS_BASER_InnerShareable;
22942323
u64 cache = GITS_BASER_RaWaWb;
2295-
u32 psz = SZ_64K;
22962324
int err, i;
22972325

22982326
if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375)
@@ -2303,16 +2331,22 @@ static int its_alloc_tables(struct its_node *its)
23032331
struct its_baser *baser = its->tables + i;
23042332
u64 val = its_read_baser(its, baser);
23052333
u64 type = GITS_BASER_TYPE(val);
2306-
u32 order = get_order(psz);
23072334
bool indirect = false;
2335+
u32 order;
23082336

2309-
switch (type) {
2310-
case GITS_BASER_TYPE_NONE:
2337+
if (type == GITS_BASER_TYPE_NONE)
23112338
continue;
23122339

2340+
if (its_probe_baser_psz(its, baser)) {
2341+
its_free_tables(its);
2342+
return -ENXIO;
2343+
}
2344+
2345+
order = get_order(baser->psz);
2346+
2347+
switch (type) {
23132348
case GITS_BASER_TYPE_DEVICE:
2314-
indirect = its_parse_indirect_baser(its, baser,
2315-
psz, &order,
2349+
indirect = its_parse_indirect_baser(its, baser, &order,
23162350
device_ids(its));
23172351
break;
23182352

@@ -2328,20 +2362,18 @@ static int its_alloc_tables(struct its_node *its)
23282362
}
23292363
}
23302364

2331-
indirect = its_parse_indirect_baser(its, baser,
2332-
psz, &order,
2365+
indirect = its_parse_indirect_baser(its, baser, &order,
23332366
ITS_MAX_VPEID_BITS);
23342367
break;
23352368
}
23362369

2337-
err = its_setup_baser(its, baser, cache, shr, psz, order, indirect);
2370+
err = its_setup_baser(its, baser, cache, shr, order, indirect);
23382371
if (err < 0) {
23392372
its_free_tables(its);
23402373
return err;
23412374
}
23422375

23432376
/* Update settings which will be used for next BASERn */
2344-
psz = baser->psz;
23452377
cache = baser->val & GITS_BASER_CACHEABILITY_MASK;
23462378
shr = baser->val & GITS_BASER_SHAREABILITY_MASK;
23472379
}

0 commit comments

Comments
 (0)