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

Configure Feed

Select the types of activity you want to include in your feed.

arm_mpam: Add workaround for T241-MPAM-1

The MPAM bandwidth partitioning controls will not be correctly configured,
and hardware will retain default configuration register values, meaning
generally that bandwidth will remain unprovisioned.

To address the issue, follow the below steps after updating the MBW_MIN
and/or MBW_MAX registers.

- Perform 64b reads from all 12 bridge MPAM shadow registers at offsets
(0x360048 + slice*0x10000 + partid*8). These registers are read-only.
- Continue iterating until all 12 shadow register values match in a loop.
pr_warn_once if the values fail to match within the loop count 1000.
- Perform 64b writes with the value 0x0 to the two spare registers at
offsets 0x1b0000 and 0x1c0000.

In the hardware, writes to the MPAMCFG_MBW_MAX MPAMCFG_MBW_MIN registers
are transformed into broadcast writes to the 12 shadow registers. The
final two writes to the spare registers cause a final rank of downstream
micro-architectural MPAM registers to be updated from the shadow copies.
The intervening loop to read the 12 shadow registers helps avoid a race
condition where writes to the spare registers occur before all shadow
registers have been updated.

Tested-by: Gavin Shan <gshan@redhat.com>
Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
Tested-by: Jesse Chick <jessechick@os.amperecomputing.com>
Reviewed-by: Zeng Heng <zengheng4@huawei.com>
Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>

authored by

Shanker Donthineni and committed by
James Morse
70e81fbe fa774521

+99
+2
Documentation/arch/arm64/silicon-errata.rst
··· 247 247 +----------------+-----------------+-----------------+-----------------------------+ 248 248 | NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A | 249 249 +----------------+-----------------+-----------------+-----------------------------+ 250 + | NVIDIA | T241 MPAM | T241-MPAM-1 | N/A | 251 + +----------------+-----------------+-----------------+-----------------------------+ 250 252 +----------------+-----------------+-----------------+-----------------------------+ 251 253 | Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 | 252 254 +----------------+-----------------+-----------------+-----------------------------+
+88
drivers/resctrl/mpam_devices.c
··· 29 29 30 30 #include "mpam_internal.h" 31 31 32 + /* Values for the T241 errata workaround */ 33 + #define T241_CHIPS_MAX 4 34 + #define T241_CHIP_NSLICES 12 35 + #define T241_SPARE_REG0_OFF 0x1b0000 36 + #define T241_SPARE_REG1_OFF 0x1c0000 37 + #define T241_CHIP_ID(phys) FIELD_GET(GENMASK_ULL(44, 43), phys) 38 + #define T241_SHADOW_REG_OFF(sidx, pid) (0x360048 + (sidx) * 0x10000 + (pid) * 8) 39 + #define SMCCC_SOC_ID_T241 0x036b0241 40 + static void __iomem *t241_scratch_regs[T241_CHIPS_MAX]; 41 + 32 42 /* 33 43 * mpam_list_lock protects the SRCU lists when writing. Once the 34 44 * mpam_enabled key is enabled these lists are read-only, ··· 640 630 return ERR_PTR(-ENOENT); 641 631 } 642 632 633 + static int mpam_enable_quirk_nvidia_t241_1(struct mpam_msc *msc, 634 + const struct mpam_quirk *quirk) 635 + { 636 + s32 soc_id = arm_smccc_get_soc_id_version(); 637 + struct resource *r; 638 + phys_addr_t phys; 639 + 640 + /* 641 + * A mapping to a device other than the MSC is needed, check 642 + * SOC_ID is NVIDIA T241 chip (036b:0241) 643 + */ 644 + if (soc_id < 0 || soc_id != SMCCC_SOC_ID_T241) 645 + return -EINVAL; 646 + 647 + r = platform_get_resource(msc->pdev, IORESOURCE_MEM, 0); 648 + if (!r) 649 + return -EINVAL; 650 + 651 + /* Find the internal registers base addr from the CHIP ID */ 652 + msc->t241_id = T241_CHIP_ID(r->start); 653 + phys = FIELD_PREP(GENMASK_ULL(45, 44), msc->t241_id) | 0x19000000ULL; 654 + 655 + t241_scratch_regs[msc->t241_id] = ioremap(phys, SZ_8M); 656 + if (WARN_ON_ONCE(!t241_scratch_regs[msc->t241_id])) 657 + return -EINVAL; 658 + 659 + pr_info_once("Enabled workaround for NVIDIA T241 erratum T241-MPAM-1\n"); 660 + 661 + return 0; 662 + } 663 + 643 664 static const struct mpam_quirk mpam_quirks[] = { 665 + { 666 + /* NVIDIA t241 erratum T241-MPAM-1 */ 667 + .init = mpam_enable_quirk_nvidia_t241_1, 668 + .iidr = MPAM_IIDR_NVIDIA_T241, 669 + .iidr_mask = MPAM_IIDR_MATCH_ONE, 670 + .workaround = T241_SCRUB_SHADOW_REGS, 671 + }, 644 672 { NULL } /* Sentinel */ 645 673 }; 646 674 ··· 1426 1378 __mpam_write_reg(msc, reg, bm); 1427 1379 } 1428 1380 1381 + static void mpam_apply_t241_erratum(struct mpam_msc_ris *ris, u16 partid) 1382 + { 1383 + int sidx, i, lcount = 1000; 1384 + void __iomem *regs; 1385 + u64 val0, val; 1386 + 1387 + regs = t241_scratch_regs[ris->vmsc->msc->t241_id]; 1388 + 1389 + for (i = 0; i < lcount; i++) { 1390 + /* Read the shadow register at index 0 */ 1391 + val0 = readq_relaxed(regs + T241_SHADOW_REG_OFF(0, partid)); 1392 + 1393 + /* Check if all the shadow registers have the same value */ 1394 + for (sidx = 1; sidx < T241_CHIP_NSLICES; sidx++) { 1395 + val = readq_relaxed(regs + 1396 + T241_SHADOW_REG_OFF(sidx, partid)); 1397 + if (val != val0) 1398 + break; 1399 + } 1400 + if (sidx == T241_CHIP_NSLICES) 1401 + break; 1402 + } 1403 + 1404 + if (i == lcount) 1405 + pr_warn_once("t241: inconsistent values in shadow regs"); 1406 + 1407 + /* Write a value zero to spare registers to take effect of MBW conf */ 1408 + writeq_relaxed(0, regs + T241_SPARE_REG0_OFF); 1409 + writeq_relaxed(0, regs + T241_SPARE_REG1_OFF); 1410 + } 1411 + 1412 + static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid, 1413 + struct mpam_config *cfg) 1414 + { 1415 + if (mpam_has_quirk(T241_SCRUB_SHADOW_REGS, ris->vmsc->msc)) 1416 + mpam_apply_t241_erratum(ris, partid); 1417 + } 1418 + 1429 1419 /* Called via IPI. Call while holding an SRCU reference */ 1430 1420 static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, 1431 1421 struct mpam_config *cfg) ··· 1542 1456 1543 1457 mpam_write_partsel_reg(msc, PRI, pri_val); 1544 1458 } 1459 + 1460 + mpam_quirk_post_config_change(ris, partid, cfg); 1545 1461 1546 1462 mutex_unlock(&msc->part_sel_lock); 1547 1463 }
+9
drivers/resctrl/mpam_internal.h
··· 130 130 void __iomem *mapped_hwpage; 131 131 size_t mapped_hwpage_sz; 132 132 133 + /* Values only used on some platforms for quirks */ 134 + u32 t241_id; 135 + 133 136 struct mpam_garbage garbage; 134 137 }; 135 138 ··· 223 220 224 221 /* Workaround bits for msc->quirks */ 225 222 enum mpam_device_quirks { 223 + T241_SCRUB_SHADOW_REGS, 226 224 MPAM_QUIRK_LAST 227 225 }; 228 226 ··· 243 239 FIELD_PREP_CONST(MPAMF_IIDR_VARIANT, 0xf) | \ 244 240 FIELD_PREP_CONST(MPAMF_IIDR_REVISION, 0xf) | \ 245 241 FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff)) 242 + 243 + #define MPAM_IIDR_NVIDIA_T241 (FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID, 0x241) | \ 244 + FIELD_PREP_CONST(MPAMF_IIDR_VARIANT, 0) | \ 245 + FIELD_PREP_CONST(MPAMF_IIDR_REVISION, 0) | \ 246 + FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b)) 246 247 247 248 /* The values for MSMON_CFG_MBWU_FLT.RWBW */ 248 249 enum mon_filter_options {