Skip to content

Commit 70e81fb

Browse files
shankerd04James Morse
authored andcommitted
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>
1 parent fa77452 commit 70e81fb

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

Documentation/arch/arm64/silicon-errata.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ stable kernels.
247247
+----------------+-----------------+-----------------+-----------------------------+
248248
| NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A |
249249
+----------------+-----------------+-----------------+-----------------------------+
250+
| NVIDIA | T241 MPAM | T241-MPAM-1 | N/A |
251+
+----------------+-----------------+-----------------+-----------------------------+
250252
+----------------+-----------------+-----------------+-----------------------------+
251253
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
252254
+----------------+-----------------+-----------------+-----------------------------+

drivers/resctrl/mpam_devices.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929

3030
#include "mpam_internal.h"
3131

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+
3242
/*
3343
* mpam_list_lock protects the SRCU lists when writing. Once the
3444
* mpam_enabled key is enabled these lists are read-only,
@@ -630,7 +640,45 @@ static struct mpam_msc_ris *mpam_get_or_create_ris(struct mpam_msc *msc,
630640
return ERR_PTR(-ENOENT);
631641
}
632642

643+
static int mpam_enable_quirk_nvidia_t241_1(struct mpam_msc *msc,
644+
const struct mpam_quirk *quirk)
645+
{
646+
s32 soc_id = arm_smccc_get_soc_id_version();
647+
struct resource *r;
648+
phys_addr_t phys;
649+
650+
/*
651+
* A mapping to a device other than the MSC is needed, check
652+
* SOC_ID is NVIDIA T241 chip (036b:0241)
653+
*/
654+
if (soc_id < 0 || soc_id != SMCCC_SOC_ID_T241)
655+
return -EINVAL;
656+
657+
r = platform_get_resource(msc->pdev, IORESOURCE_MEM, 0);
658+
if (!r)
659+
return -EINVAL;
660+
661+
/* Find the internal registers base addr from the CHIP ID */
662+
msc->t241_id = T241_CHIP_ID(r->start);
663+
phys = FIELD_PREP(GENMASK_ULL(45, 44), msc->t241_id) | 0x19000000ULL;
664+
665+
t241_scratch_regs[msc->t241_id] = ioremap(phys, SZ_8M);
666+
if (WARN_ON_ONCE(!t241_scratch_regs[msc->t241_id]))
667+
return -EINVAL;
668+
669+
pr_info_once("Enabled workaround for NVIDIA T241 erratum T241-MPAM-1\n");
670+
671+
return 0;
672+
}
673+
633674
static const struct mpam_quirk mpam_quirks[] = {
675+
{
676+
/* NVIDIA t241 erratum T241-MPAM-1 */
677+
.init = mpam_enable_quirk_nvidia_t241_1,
678+
.iidr = MPAM_IIDR_NVIDIA_T241,
679+
.iidr_mask = MPAM_IIDR_MATCH_ONE,
680+
.workaround = T241_SCRUB_SHADOW_REGS,
681+
},
634682
{ NULL } /* Sentinel */
635683
};
636684

@@ -1378,6 +1426,44 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd)
13781426
__mpam_write_reg(msc, reg, bm);
13791427
}
13801428

1429+
static void mpam_apply_t241_erratum(struct mpam_msc_ris *ris, u16 partid)
1430+
{
1431+
int sidx, i, lcount = 1000;
1432+
void __iomem *regs;
1433+
u64 val0, val;
1434+
1435+
regs = t241_scratch_regs[ris->vmsc->msc->t241_id];
1436+
1437+
for (i = 0; i < lcount; i++) {
1438+
/* Read the shadow register at index 0 */
1439+
val0 = readq_relaxed(regs + T241_SHADOW_REG_OFF(0, partid));
1440+
1441+
/* Check if all the shadow registers have the same value */
1442+
for (sidx = 1; sidx < T241_CHIP_NSLICES; sidx++) {
1443+
val = readq_relaxed(regs +
1444+
T241_SHADOW_REG_OFF(sidx, partid));
1445+
if (val != val0)
1446+
break;
1447+
}
1448+
if (sidx == T241_CHIP_NSLICES)
1449+
break;
1450+
}
1451+
1452+
if (i == lcount)
1453+
pr_warn_once("t241: inconsistent values in shadow regs");
1454+
1455+
/* Write a value zero to spare registers to take effect of MBW conf */
1456+
writeq_relaxed(0, regs + T241_SPARE_REG0_OFF);
1457+
writeq_relaxed(0, regs + T241_SPARE_REG1_OFF);
1458+
}
1459+
1460+
static void mpam_quirk_post_config_change(struct mpam_msc_ris *ris, u16 partid,
1461+
struct mpam_config *cfg)
1462+
{
1463+
if (mpam_has_quirk(T241_SCRUB_SHADOW_REGS, ris->vmsc->msc))
1464+
mpam_apply_t241_erratum(ris, partid);
1465+
}
1466+
13811467
/* Called via IPI. Call while holding an SRCU reference */
13821468
static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
13831469
struct mpam_config *cfg)
@@ -1457,6 +1543,8 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid,
14571543
mpam_write_partsel_reg(msc, PRI, pri_val);
14581544
}
14591545

1546+
mpam_quirk_post_config_change(ris, partid, cfg);
1547+
14601548
mutex_unlock(&msc->part_sel_lock);
14611549
}
14621550

drivers/resctrl/mpam_internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ struct mpam_msc {
130130
void __iomem *mapped_hwpage;
131131
size_t mapped_hwpage_sz;
132132

133+
/* Values only used on some platforms for quirks */
134+
u32 t241_id;
135+
133136
struct mpam_garbage garbage;
134137
};
135138

@@ -220,6 +223,7 @@ struct mpam_props {
220223

221224
/* Workaround bits for msc->quirks */
222225
enum mpam_device_quirks {
226+
T241_SCRUB_SHADOW_REGS,
223227
MPAM_QUIRK_LAST
224228
};
225229

@@ -240,6 +244,11 @@ struct mpam_quirk {
240244
FIELD_PREP_CONST(MPAMF_IIDR_REVISION, 0xf) | \
241245
FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0xfff))
242246

247+
#define MPAM_IIDR_NVIDIA_T241 (FIELD_PREP_CONST(MPAMF_IIDR_PRODUCTID, 0x241) | \
248+
FIELD_PREP_CONST(MPAMF_IIDR_VARIANT, 0) | \
249+
FIELD_PREP_CONST(MPAMF_IIDR_REVISION, 0) | \
250+
FIELD_PREP_CONST(MPAMF_IIDR_IMPLEMENTER, 0x36b))
251+
243252
/* The values for MSMON_CFG_MBWU_FLT.RWBW */
244253
enum mon_filter_options {
245254
COUNT_BOTH = 0,

0 commit comments

Comments
 (0)