From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E40091F3D56 for ; Sun, 2 Aug 2026 16:17:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785687479; cv=none; b=gHe17c2Qj79x5JSBqwjSi3Us015Y8sV64aHjLGE2dcuQcyVdqpiPmq+IT92w5V+tC2ewDS/Ldd1MH9P2lryC4rCqOrGO5kAc5d3v7VMDKodRifhKDi6VPaa77PC7QPWsIHk8nGU+rCOZtK14hlPDqjtDs8IoL3zen8z28t6plXE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785687479; c=relaxed/simple; bh=zHyXiUGhoXY4UThAuxejT6j1l3ZuYZUpoIFHq9NfuTo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=lE57unVKUDMAm6gEhg703aO/bwfSwFXZGxn0l4I//FwL6j2Zl1OapUS0BG3mwoYXo+iIbbKuSLeCSxXqKtJy/5uvCLVtGNdo6M0Kqy01zMwAChLEi7wD42XqxCs7yXL7qLqFR7em648+2kUGVoPKV4GsBFv2vLOMVzQxVT4mIW0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=e/180tJq; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="e/180tJq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1785687474; x=1817223474; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zHyXiUGhoXY4UThAuxejT6j1l3ZuYZUpoIFHq9NfuTo=; b=e/180tJqgqUIJXBPVJXGHKN6cgVG/oBz5J4x5d4UdPt15UIqGou15LY5 uEkuV26/9F0Fiis1LC7Crb3XpWSmBIpQvqZpOjpX+heETT0GwqBPQaNaN /YfoaZsp4WCPj1+bc9GblszKE6vXpMOjE/ebtU9Brb2C33599e+hwhlew 3y6XPztxemEJ8wKlQ/uY1QQZ1m8o3ynv9yf3qFbM28Gvt9hRt3v7K6F4E Hxq1ihwFmZYmCwJ+Bjxd88wj8UkgupYRDJTx/YJpsc13PJyKQnK013MwW TFhjIL4B5foDpN/9moZrbD9np7gRnZbnRy7H2p6IaEU5acIso+f1Zek3E Q==; X-CSE-ConnectionGUID: Qm5eoauzSnqHhbFR3WEMnw== X-CSE-MsgGUID: HVgiRhYpQ3WJz+jDnT2SPA== X-IronPort-AV: E=McAfee;i="6800,10657,11863"; a="86258036" X-IronPort-AV: E=Sophos;i="6.25,200,1779174000"; d="scan'208";a="86258036" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 02 Aug 2026 09:17:50 -0700 X-CSE-ConnectionGUID: Cw8DktU9TBmuEqaKuZO8hA== X-CSE-MsgGUID: VsTy1rG3S5eqlOXAgD3NMQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,200,1779174000"; d="scan'208";a="290950366" Received: from chenyu-dev.sh.intel.com ([10.239.62.107]) by orviesa002.jf.intel.com with ESMTP; 02 Aug 2026 09:17:48 -0700 From: Chen Yu To: Reinette Chatre , Tony Luck Cc: Ben Horgan , "James Morse" , Dave Martin , Babu Moger , Fenghua Yu , Borislav Petkov , Thomas Gleixner , "Dave Hansen" , Peter Newman , chen.yu@linux.dev, x86@kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 28/31] x86/resctrl: Emulate the legacy MBA controller via the region MAX controls Date: Mon, 3 Aug 2026 00:08:06 +0800 Message-Id: <4023c8b8f84d1b896d46b56dd3737ec96325ac3a.1785680802.git.yu.c.chen@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit On ERDT platforms the legacy MBA "default" controller does have hardware of its own, but the region-based MAX controllers are the preferred way to throttle memory bandwidth. Rather than programming the legacy MSR, realize the default controller's effect through the MAX controller of every memory region, which keeps a single consistent throttling mechanism in use. Link the default controller to the MAX controller of every available region via resctrl_ctrl::emul in erdt_get_mem_config() so they are associated once the controllers are created. Route the arch control writes accordingly. When a control is emulated (ctrl->emul is not empty), do not program the legacy MSR; instead translate the configured value into each emulation controller's units and program that controller's hardware. Signed-off-by: Chen Yu --- arch/x86/kernel/cpu/resctrl/ctrlmondata.c | 75 ++++++++++++++++++++--- arch/x86/kernel/cpu/resctrl/erdt.c | 18 ++++++ include/linux/resctrl.h | 3 + 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c index 7bacb8bf2e27..7fe48912d2d5 100644 --- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c +++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c @@ -28,6 +28,48 @@ static void ctrl_hw_update(struct resctrl_ctrl *ctrl, struct rdt_ctrl_domain *d, smp_call_function_any(&d->hdr.cpu_mask, rdt_ctrl_update, m, 1); } +static u32 emul_translate_val(struct resctrl_ctrl *src, struct resctrl_ctrl *dst, + u32 val) +{ + return val * dst->scalar.max_bw / src->scalar.max_bw; +} + +static void _resctrl_arch_update_emul(struct rdt_resource *r, + struct resctrl_ctrl *ctrl, + struct rdt_ctrl_domain *d, u32 low, u32 high) +{ + struct rdt_hw_ctrl_domain *emul_hw_dom; + struct rdt_hw_ctrl_domain *hw_dom; + struct rdt_ctrl_domain *emul_d; + struct resctrl_ctrl *emul; + struct rdt_domain_hdr *hdr; + struct hw_param emul_param; + unsigned int i; + + hw_dom = resctrl_to_arch_ctrl_dom(d); + + for_each_emul_ctrl(emul, ctrl) { + hdr = resctrl_find_domain(&emul->domains, d->hdr.id, NULL); + if (!hdr) + continue; + + emul_d = container_of(hdr, struct rdt_ctrl_domain, hdr); + emul_hw_dom = resctrl_to_arch_ctrl_dom(emul_d); + + for (i = low; i < high; i++) + emul_hw_dom->ctrl_val[i] = emul_translate_val(ctrl, emul, + hw_dom->ctrl_val[i]); + + emul_param.res = r; + emul_param.ctrl = emul; + emul_param.dom = emul_d; + emul_param.low = low; + emul_param.high = high; + + ctrl_hw_update(emul, emul_d, &emul_param); + } +} + int resctrl_arch_update_one(struct rdt_resource *r, struct resctrl_ctrl *ctrl, struct rdt_ctrl_domain *d, u32 closid, enum resctrl_conf_type t, u32 cfg_val) @@ -42,12 +84,20 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct resctrl_ctrl *ctrl, hw_dom->ctrl_val[idx] = cfg_val; - hw_param.res = r; - hw_param.ctrl = ctrl; - hw_param.dom = d; - hw_param.low = idx; - hw_param.high = idx + 1; - hw_ctrl->hw_update(&hw_param); + /* + * When this control is emulated, program the emulation controllers' + * hardware instead. + */ + if (!list_empty(&ctrl->emul)) { + _resctrl_arch_update_emul(r, ctrl, d, idx, idx + 1); + } else { + hw_param.res = r; + hw_param.ctrl = ctrl; + hw_param.dom = d; + hw_param.low = idx; + hw_param.high = idx + 1; + hw_ctrl->hw_update(&hw_param); + } return 0; } @@ -89,8 +139,17 @@ static void _resctrl_arch_update_domains(struct rdt_resource *r, hw_param.high = max(hw_param.high, idx + 1); } } - if (hw_param.res) - ctrl_hw_update(ctrl, d, &hw_param); + if (hw_param.res) { + /* + * When this control is emulated, program the emulation + * controllers' hardware instead. + */ + if (!list_empty(&ctrl->emul)) + _resctrl_arch_update_emul(r, ctrl, d, + hw_param.low, hw_param.high); + else + ctrl_hw_update(ctrl, d, &hw_param); + } } } diff --git a/arch/x86/kernel/cpu/resctrl/erdt.c b/arch/x86/kernel/cpu/resctrl/erdt.c index 6464463973bb..4515e3251476 100644 --- a/arch/x86/kernel/cpu/resctrl/erdt.c +++ b/arch/x86/kernel/cpu/resctrl/erdt.c @@ -325,6 +325,7 @@ static void marc_hw_update(struct hw_param *m) __init bool erdt_get_mem_config(struct rdt_resource *r) { struct rdt_hw_resource *hw_res = resctrl_to_arch_res(r); + struct resctrl_ctrl *def_ctrl = NULL, *ctrl; struct resctrl_hw_ctrl *hw_ctrl; struct erdt_domain_info *d; struct acpi_erdt_marc *marc; @@ -343,6 +344,13 @@ __init bool erdt_get_mem_config(struct rdt_resource *r) max_regions = acpi_mrrm_max_mem_region(); hw_res->num_closid = max(hw_res->num_closid, erdt_max_clos + 1); + for_each_resource_ctrl(ctrl, r) { + if (ctrl->name == RESCTRL_CTRL_NAME_DEF) { + def_ctrl = ctrl; + break; + } + } + for (region = 0; region < max_regions; region++) { for (type = RESCTRL_CTRL_REGION_TYPE_OPT; type < RESCTRL_CTRL_REGION_NR_CTRLS; type++) { if (type == RESCTRL_CTRL_REGION_TYPE_OPT && !(marc->flags & MARC_FLAG_OPT)) @@ -374,6 +382,16 @@ __init bool erdt_get_mem_config(struct rdt_resource *r) /* MARC controls live in MMIO, program from any CPU. */ hw_ctrl->r_ctrl.flags |= RESCTRL_CTRL_FLAG_ANY_CPU; list_add_tail(&hw_ctrl->r_ctrl.entry, &r->controls); + + /* + * Throttle memory bandwidth through the region MAX + * controls rather than the legacy MBA MSR, so let the + * MAX control of every region emulate the legacy MBA + * control. + */ + if (def_ctrl && type == RESCTRL_CTRL_REGION_TYPE_MAX) + list_add_tail(&hw_ctrl->r_ctrl.emul_entry, + &def_ctrl->emul); } } diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 8260b09aa323..57615af637ad 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -51,6 +51,9 @@ int proc_resctrl_show(struct seq_file *m, #define for_each_resource_ctrl(ctrl, r) \ list_for_each_entry(ctrl, &r->controls, entry) +#define for_each_emul_ctrl(emul, ctrl) \ + list_for_each_entry(emul, &ctrl->emul, emul_entry) + enum resctrl_res_level { RDT_RESOURCE_L3, RDT_RESOURCE_L2, -- 2.43.0