From patchwork Thu Nov 7 20:58:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867132 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 769A9218330; Thu, 7 Nov 2024 20:58:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013113; cv=none; b=EPw7p4O1S8G4nip+lYFQXXV75/d3sw66DkLxOrSauMueOX5TNL6hhBoE1EkGAz2aA7XDRTsrIJrOwNXCRWpCywKSpIVZYypNpLZivahBXhysMOIylNtyS1StPFfZVjEI4vaqIz9eH+RBh+mgeBvhSyICl5MTLe08vTCQkHouDm8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013113; c=relaxed/simple; bh=94mNaBSKBGKU/oxXHv0KQQ3HrmkwrIQ1mGVq1crl7PM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=tBXfwz/afCAsH0qdK99cyHyCZEU01gonBHy2Rfs6v5Jz+0V5VlsgBsmfXzcUx0GoKrUxGrslOHUcPEBJpd95wQ+XcpUX6xHPMJ0mwVhX1VdQnsawxIeEF11GbN3iBSe8/DtFlVts2RnMPYfHj37prHczu5HNOwNGjM6DZvH13Qk= 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=ElWU+EHp; arc=none smtp.client-ip=192.198.163.18 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="ElWU+EHp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013112; x=1762549112; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=94mNaBSKBGKU/oxXHv0KQQ3HrmkwrIQ1mGVq1crl7PM=; b=ElWU+EHpri2R/uvozMsWjWkR1QXi698JOvONE7beyk1bSpm+lhKXUzWl Wv/5SwWQRfZEHqxmxGlkr51LWxhs93/C027USswdNVt8wYVcOc7LHegJu SiMYUtOM8wnqaWuDtH3HJFoXSuMCAF6SCBv3LKmYRMZcXT/kjOF9VC1fX xZX2OQpC46PIa17r7qYk3x+iQKPLJKW5FeyZIQA49qd273ZjHJ6cS7DNx a/SuFqiK6sy6jNDdbMkbpRsJEPVxOS1w5yrNH2YIGwEK/2opDWc423qBp CnQdWlgv+UfXRVCI1La+4g7SpEEbN0XkWcQcUfiG04Ec0ZquSfQGYlPTP Q==; X-CSE-ConnectionGUID: sTdqaSG6SP2g//rYy0aZug== X-CSE-MsgGUID: PoOGLGUiTwG6JXM80Fm1bg== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300304" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300304" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:31 -0800 X-CSE-ConnectionGUID: n2IJ74b0Qe+lizxmBhiMtw== X-CSE-MsgGUID: xJGMfSZzSWqhEHrSMlRm6w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093559" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:29 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:19 -0600 Subject: [PATCH v7 01/27] range: Add range_overlaps() Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-1-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Chris Mason , Josef Bacik , David Sterba , linux-btrfs@vger.kernel.org, Johannes Thumshirn X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=3560; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=94mNaBSKBGKU/oxXHv0KQQ3HrmkwrIQ1mGVq1crl7PM=; b=FjTQQBlIrjX+U8Sga2DcTPBulTU64M2NoB3Mndc7uk7/8hf3Lld+UBhhiburKhf6EPtFXuQHR 9I75UxIkXOvCv8QxYfJJRQjOBTVnQaqH6K7dPfVj8BGbvpRBVhglgXG X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Code to support CXL Dynamic Capacity devices will have extent ranges which need to be compared for intersection not a subset as is being checked in range_contains(). range_overlaps() is defined in btrfs with a different meaning from what is required in the standard range code. Dan Williams pointed this out in [1]. Adjust the btrfs call according to his suggestion there. Then add a generic range_overlaps(). Cc: Dan Williams Cc: Chris Mason Cc: Josef Bacik Cc: David Sterba Cc: linux-btrfs@vger.kernel.org Link: https://lore.kernel.org/all/65949f79ef908_8dc68294f2@dwillia2-xfh.jf.intel.com.notmuch/ [1] Acked-by: David Sterba Reviewed-by: Davidlohr Bueso Reviewed-by: Johannes Thumshirn Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Signed-off-by: Ira Weiny --- fs/btrfs/ordered-data.c | 10 +++++----- include/linux/range.h | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 2104d60c216166d577ef81750c63167248f33b6a..744c3375ee6a88e0fc01ef7664e923a48cbe6dca 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c @@ -111,8 +111,8 @@ static struct rb_node *__tree_search(struct rb_root *root, u64 file_offset, return NULL; } -static int range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset, - u64 len) +static int btrfs_range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset, + u64 len) { if (file_offset + len <= entry->file_offset || entry->file_offset + entry->num_bytes <= file_offset) @@ -985,7 +985,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_range( while (1) { entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (range_overlaps(entry, file_offset, len)) + if (btrfs_range_overlaps(entry, file_offset, len)) break; if (entry->file_offset >= file_offset + len) { @@ -1114,12 +1114,12 @@ struct btrfs_ordered_extent *btrfs_lookup_first_ordered_range( } if (prev) { entry = rb_entry(prev, struct btrfs_ordered_extent, rb_node); - if (range_overlaps(entry, file_offset, len)) + if (btrfs_range_overlaps(entry, file_offset, len)) goto out; } if (next) { entry = rb_entry(next, struct btrfs_ordered_extent, rb_node); - if (range_overlaps(entry, file_offset, len)) + if (btrfs_range_overlaps(entry, file_offset, len)) goto out; } /* No ordered extent in the range */ diff --git a/include/linux/range.h b/include/linux/range.h index 6ad0b73cb7adc0ee53451b8fed0a70772adc98fa..876cd5355158eff267a42991ba17fa35a1d31600 100644 --- a/include/linux/range.h +++ b/include/linux/range.h @@ -13,11 +13,19 @@ static inline u64 range_len(const struct range *range) return range->end - range->start + 1; } +/* True if r1 completely contains r2 */ static inline bool range_contains(struct range *r1, struct range *r2) { return r1->start <= r2->start && r1->end >= r2->end; } +/* True if any part of r1 overlaps r2 */ +static inline bool range_overlaps(const struct range *r1, + const struct range *r2) +{ + return r1->start <= r2->end && r1->end >= r2->start; +} + int add_range(struct range *range, int az, int nr_range, u64 start, u64 end); From patchwork Thu Nov 7 20:58:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867133 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 BF7802185A3; Thu, 7 Nov 2024 20:58:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013115; cv=none; b=owz4aDtb6GdNdHeoDQWVcew1o2TRYCG303jl3L4erCi/mkg6ZMRkNScGS8fe8nDOuM6pYiUG7oW/hO2ZtJdZzf47LEim5Esa3urT2vPao5qRJ8oYFBgRMLqUpyFMrsiC1+8Kv49WZGa6vaYnbrMB/bYujHNK47d6fmhFCv9qfF8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013115; c=relaxed/simple; bh=cSMvJkX51N5SZd4M/a76wB0H3R/PAuQxBIejQHOLvpQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZYPsNp6ed6NrB39HmG1fWw6wrrSouu0zx1WYP41ETdL/GvYNfoH0T+uHC754X3wmua7xKI5PjHenZFn5JkIosMmU6TjLyRfBFDdivpnbUo33rh2DomQRmuXM8qxbEwMRAmPmpYgXzOmHpBOi5z2/wqiX0OGYGZkbt8HWaTcmmh8= 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=cgqWGMrR; arc=none smtp.client-ip=192.198.163.18 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="cgqWGMrR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013114; x=1762549114; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=cSMvJkX51N5SZd4M/a76wB0H3R/PAuQxBIejQHOLvpQ=; b=cgqWGMrRqzCfhY8EJcqQb2Y7O+k0gEv5oifSIHUAa43NCtmOtGviRSEh iqIVgFLsm6bXES2chAufqKmDj5Ij45zAeDO16wG72k5m9VyvLnLvEoqSU 8lzBOHNx0oNk22PmEQqemBpZQ4CTwfaiBx4B0TgmuncdiMwqMmr0zlfZd +Jn+asWwMrAncXKFCSPBBigSXoD3JJyXX2UFCNbJajaOGrZvmSS525/V8 s+PPAmOzTj5tH+R6dskNET8u57bVi7TZAm2aeXypfkAcIuTwSZDstU2K0 Zy9zL9aee1Xh+BAmpqGeZBQ6wcC4OofqmjpfnxI5PKtNJ6pXJ1qPXrmjn A==; X-CSE-ConnectionGUID: kt6V8aHURfC0RZb4HNNgOg== X-CSE-MsgGUID: C5enpCHqS3G+TZ56OWCKFw== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300317" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300317" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:33 -0800 X-CSE-ConnectionGUID: JVKLk2P4TLSaUd1DIFL9SA== X-CSE-MsgGUID: zxiGuk0jSZee4Mz22ZEHeg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093588" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:32 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:20 -0600 Subject: [PATCH v7 02/27] ACPI/CDAT: Add CDAT/DSMAS shared and read only flag values Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-2-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Robert Moore , Len Brown , "Rafael J. Wysocki" , linux-acpi@vger.kernel.org, acpica-devel@lists.linux.dev X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=1396; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=cSMvJkX51N5SZd4M/a76wB0H3R/PAuQxBIejQHOLvpQ=; b=z2BQlqBVQRzSIOea9aSZ3mKia0/yYjWvDVWSXOZmb9+T/4l35RyKgajzpDqsbaka1Sb+agahK anSxXg8dEN1DYqTcqqUY9ZV2pc/Vxksjh6VyGDUIWV6MiqayH97WPkG X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= The Coherent Device Attribute Table (CDAT) Device Scoped Memory Affinity Structure (DSMAS) version 1.04 [1] defines flags to indicate if a DPA range is read only and/or shared. Add read only and shareable flag definitions. This change was merged in ACPICA via PR 976.[2] Link: https://uefi.org/sites/default/files/resources/Coherent%20Device%20Attribute%20Table_1.04%20published_0.pdf [1] Link: https://github.com/acpica/acpica/pull/976 [2] Cc: Robert Moore Cc: Len Brown Cc: Rafael J. Wysocki Cc: linux-acpi@vger.kernel.org Cc: acpica-devel@lists.linux.dev Acked-by: Rafael J. Wysocki Signed-off-by: Ira Weiny --- include/acpi/actbl1.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h index 199afc2cd122ca8b383b1c9286f8c8cc33842fae..387fc821703a80b324637743f0d5afe03b8d7943 100644 --- a/include/acpi/actbl1.h +++ b/include/acpi/actbl1.h @@ -403,6 +403,8 @@ struct acpi_cdat_dsmas { /* Flags for subtable above */ #define ACPI_CDAT_DSMAS_NON_VOLATILE (1 << 2) +#define ACPI_CDAT_DSMAS_SHAREABLE (1 << 3) +#define ACPI_CDAT_DSMAS_READ_ONLY (1 << 6) /* Subtable 1: Device scoped Latency and Bandwidth Information Structure (DSLBIS) */ From patchwork Thu Nov 7 20:58:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867134 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 012C821949D; Thu, 7 Nov 2024 20:58:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013118; cv=none; b=agr38qXsalR8zT0svmB5S6AcuBhWL9sOQ1qQo8Fp6iGYcybEDazmUPkenQsavmCFZUURGZ36LZ3b3cvE5BRhbfc3DsMMKFRjKBtSB2R/EY9jFCk1daSZvVZzOJlxgj/lT2zkIDsO6pvjsb/3rc0UOiN3Amx9eiJnVcb0Mx3ldMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013118; c=relaxed/simple; bh=gfJbRpeGKgtSOBlBPI7Q67kRAUKRjyjICp8gVsI2eFA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DaQjWr4uFpzgpTIzFQt2rBjcDsTh/GL8mppPYrhXF/Q4NPvRK/4X1h/NFpyqN31oeZDfPs2xcADRGdfcfcloAM6T7yMHecAgg9wxr54BB4FouDxn6Z3AX/B8/32ZSWu4ViaySG/PS6tLosq7F3N4cRQdgxPhQt1VsdoeIbpuPbY= 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=DpQbZiYU; arc=none smtp.client-ip=192.198.163.18 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="DpQbZiYU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013116; x=1762549116; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=gfJbRpeGKgtSOBlBPI7Q67kRAUKRjyjICp8gVsI2eFA=; b=DpQbZiYUrPllCpNfB5vIUFB1Zig53suCnCzIc4CN5/TsJ7ARX+8RJ01Z AEcE2I2AKl9kUbSXHc5BMzj9ovsmtY4CjzePoWLZ5mjSsafeafPDDl/Nv S3nGy+22X2g8UJejuhgigi1CMBNdNEJYJGpzvvoTaSCmbnuh+zEe6JCvx X/TI9ary6tN9jeM75FfVtpai5bklgMQ15qMb8PoT4bWm3KDQG3+DtWRWm H4O45gZxdpov3EMBD9xUdCWz5rj5oA+EQr3o7c+iSKsB2R7zq5xByLL02 MGUBVUg0+X1l1QIpJX9EABuZ+WaFkx5OMiSFDoTpiupU+QXFOP3mnaa5D w==; X-CSE-ConnectionGUID: +hYNa8a9TqS2L5/AwAurbA== X-CSE-MsgGUID: rLoJXOpFTkOblC0iSnDOKg== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300326" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300326" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:36 -0800 X-CSE-ConnectionGUID: CbT4nUaOREyMUgU37MZcKA== X-CSE-MsgGUID: xgAhoK7bRQa1u/6kgzT8Mw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093595" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:34 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:21 -0600 Subject: [PATCH v7 03/27] dax: Document struct dev_dax_range Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-3-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=2335; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=gfJbRpeGKgtSOBlBPI7Q67kRAUKRjyjICp8gVsI2eFA=; b=g3T3ttDcyk15iq52gDRXIKCO20CiEumkB8taNJNZgHrtuiZhv6fJpwUEGDflcnd6EXWJjFGS6 4goDnO8EN1HCHxPIEqRcocUOjzXr7XZaXDtXz2OyTDfS4zkgBiisIPY X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= The device DAX structure is being enhanced to track additional DCD information. Specifically the range tuple needs additional parameters. The current range tuple is not fully documented and is large enough to warrant its own definition. Separate the struct dax_dev_range definition and document it prior to adding information for DC. Suggested-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Signed-off-by: Ira Weiny --- drivers/dax/dax-private.h | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 446617b73aeab2e6f5a2ec3ca4c3f740e1b3e719..0867115aeef2e1b2d4c88b5c38b6648a404b1060 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -40,12 +40,30 @@ struct dax_region { struct device *youngest; }; +/** + * struct dax_mapping - device to display mapping range attributes + * @dev: device representing this range + * @range_id: index within dev_dax ranges array + * @id: ida of this mapping + */ struct dax_mapping { struct device dev; int range_id; int id; }; +/** + * struct dev_dax_range - tuple represenging a range of memory used by dev_dax + * @pgoff: page offset + * @range: resource-span + * @mapping: reference to the dax_mapping for this range + */ +struct dev_dax_range { + unsigned long pgoff; + struct range range; + struct dax_mapping *mapping; +}; + /** * struct dev_dax - instance data for a subdivision of a dax region, and * data while the device is activated in the driver. @@ -58,7 +76,7 @@ struct dax_mapping { * @dev - device core * @pgmap - pgmap for memmap setup / lifetime (driver owned) * @nr_range: size of @ranges - * @ranges: resource-span + pgoff tuples for the instance + * @ranges: range tuples of memory used */ struct dev_dax { struct dax_region *region; @@ -72,11 +90,7 @@ struct dev_dax { struct dev_pagemap *pgmap; bool memmap_on_memory; int nr_range; - struct dev_dax_range { - unsigned long pgoff; - struct range range; - struct dax_mapping *mapping; - } *ranges; + struct dev_dax_range *ranges; }; /* From patchwork Thu Nov 7 20:58:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867135 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 72A972185AF; Thu, 7 Nov 2024 20:58:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013120; cv=none; b=Rb1i9bcEzuPzoIFcLkvv4SVPi0/JD9v3G0Noz5gEJuGfFrYhL9Hkzk5jeG7Ay4ZeNbqQCdjykO2vBnw8YeoFj+HCzVJDQvs02ltIe+H2zWoQ2jR8jd93m4622nw1vbeEc7YMU4n4/g610DBcB7M6AtEli/5RcKzXbd3ga9zfUQk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013120; c=relaxed/simple; bh=zrkJPQVXZsx8rimt+5mECl38V/+5uCzh28VzTSmy1KA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GzyjZX8euHloz88vTE/o2/2B2JvPg7OaLjEt2xCxNHknfiwifKGfg4vnSeFGCWMTaB0KE/hKAlwI0FG0T78yNo7IPN5wlWfSrDaWz8siBdZFg0bh6jY6vyc+ESG2Sre4A1LM8QJujVFMiXHf9lpJzlIJzZ/mPa9pppm9X0OgTs0= 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=E2Bh/0MX; arc=none smtp.client-ip=192.198.163.18 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="E2Bh/0MX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013118; x=1762549118; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=zrkJPQVXZsx8rimt+5mECl38V/+5uCzh28VzTSmy1KA=; b=E2Bh/0MXhaicYbb6vLgQo3s43roEWD2v/xfrCcJHuAni9dwHgPF0lB7b bkXi/1ECQ1VkpxGo/YUfnZ5UTn0oSADxHADnZqBuzxUETWZtcohbm9qtW Ip4bC+yqe/YbL59x8QBxJOvyeD0ZNHXte1azi2zLGfFXeqKTanYAroXWq dwMZQXd0vkuhfSxkNqNTudyf2rB4uAn8GhlvF4x89Qi6tBN/BMwPd9gfO fzfIa6sZnB9jWqjFjk2lllKg5VOeYZjAMeR/1XsprWRSzAdc7ZvXi1LDX XIrmbmflpVIdZg0MlObmpeoqPzhC78EYjlHhlLSNxR7+HhD+k3gRx4Cxh Q==; X-CSE-ConnectionGUID: KefmN98ZTA6NB6VDuSS+UA== X-CSE-MsgGUID: yA9xbidAR6i2tMPsjGfynA== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300335" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300335" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:38 -0800 X-CSE-ConnectionGUID: ooMkMyDHQIGZpA3pHm+lTw== X-CSE-MsgGUID: CFx1p6rRQ/m1T//7Yz+F/g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093602" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:37 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:22 -0600 Subject: [PATCH v7 04/27] cxl/pci: Delay event buffer allocation Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-4-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=1469; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=zrkJPQVXZsx8rimt+5mECl38V/+5uCzh28VzTSmy1KA=; b=gnuvNin8o92+zuWymm375kanSqfq7hQ4bjMtJFrImeR2pRa47mHQ5N92Ojo7Unwz1VAOuVhRP kNCsGMnLFYhBaE8VmgskGIR93Nueu4uhlcUntPicw+++1Ff8quthO2S X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= The event buffer does not need to be allocated if something has failed in setting up event irq's. In prep for adjusting event configuration for DCD events move the buffer allocation to the end of the event configuration. Reviewed-by: Davidlohr Bueso Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Li Ming Link: https://lore.kernel.org/all/663922b475e50_d54d72945b@dwillia2-xfh.jf.intel.com.notmuch/ [1] Suggested-by: Dan Williams Signed-off-by: Ira Weiny --- drivers/cxl/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 188412d45e0d266b19f7401a1cdc51ed6fb0ea0a..295779c433b2a2e377995b53a70ff2a3158b0a8e 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -764,10 +764,6 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, return 0; } - rc = cxl_mem_alloc_event_buf(mds); - if (rc) - return rc; - rc = cxl_event_get_int_policy(mds, &policy); if (rc) return rc; @@ -781,6 +777,10 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, return -EBUSY; } + rc = cxl_mem_alloc_event_buf(mds); + if (rc) + return rc; + rc = cxl_event_irqsetup(mds); if (rc) return rc; From patchwork Thu Nov 7 20:58:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867136 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 4213D21A4B2; Thu, 7 Nov 2024 20:58:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013123; cv=none; b=sJzjKnZemUcbVsqHprccSy7L7U/0zHb1k5UY0DRrus/rPQ1Yu2dEegTNP+aiA6YFRrJLs3AwnOErTY2eTqJYNjBplHMZ/a+CN44SX8mqxsn8y99EgiupXNfiZh3s95CYTKgBgivqVx2mb26JBgZtUC9mjDHBesDaqbt33XzbtK4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013123; c=relaxed/simple; bh=LLABFCK37K/MhI03Fb+yWDspPbVRYojKovJHMZlMT18=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RScxpfpArGZmqJ7zc6qNw7YTvvCfExvHDE8Lyf69g5d40QgA/gY5uhhgmcn8D0dBx8gifF7thAWAAviBSDHBquL4/E1zpUV3MPNzZEoBDEeNIQZbJkDdkHSe900FfnzVcpVBmZHO3cSCegppn6Ww6XO2Gu8ASpxznV8oQdmFgDg= 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=EBngy4r7; arc=none smtp.client-ip=192.198.163.18 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="EBngy4r7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013121; x=1762549121; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=LLABFCK37K/MhI03Fb+yWDspPbVRYojKovJHMZlMT18=; b=EBngy4r7C/0UL6wwpjoY52Fa8iVcWxMESdGi0Y5LXfFfw/wpY8+LrZsv hgZ7yLbXaNBfMj2zcvaByXvcmlYP9vUEBu1SH6xOLAkyJLD8yLDp+n4RD DMYtSuOQpS0HpjB0HShIostxUuaZut7C1F187VW8uhWam1VXVve9yzZ3j 3bgh8QfkhLrNfMme0RuuL3P0RZHLOAI7PfDWUU+Y6VTzOaC82/6SmEXE8 3Q8sTCJ+lRlsX+cgHZC5GF3ZLu+M46Eh5Muhe5Z4uMO1PfUH+FYP2jcCQ 8SNqs1jkQG6fcJa2jBjcOt2sh2bzEOS3YBbKb9OzSjtHra1+kzTVOuNJY A==; X-CSE-ConnectionGUID: 6VX5jqEGSIuNM16iUwVI4Q== X-CSE-MsgGUID: aotUn4zTQfGFfnNRWeo4/Q== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300346" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300346" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:40 -0800 X-CSE-ConnectionGUID: xley0tb9TqmmrYTciajhvg== X-CSE-MsgGUID: Elgy6iYITy+D1y1G1ytgwA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093610" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:39 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:23 -0600 Subject: [PATCH v7 05/27] cxl/hdm: Use guard() in cxl_dpa_set_mode() Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-5-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Jonathan Cameron X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=2085; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=LLABFCK37K/MhI03Fb+yWDspPbVRYojKovJHMZlMT18=; b=KTcY7j4rhCzvnM1flH25sLGGRrHai72moyRVs3M3OOBwZWfMePnYfpNpfn3tgljCtRSzEsOVY lwwB8i4cSrTBiC5yPlyvg67b73nsnM3cQVJybLSEjTwljuABas9fTGT X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Additional DCD functionality is being added to this call which will be simplified by the use of guard() with the cxl_dpa_rwsem. Convert the function to use guard() prior to adding DCD functionality. Suggested-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Reviewed-by: Davidlohr Bueso Signed-off-by: Ira Weiny --- drivers/cxl/core/hdm.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 3df10517a3278f228c7535fcbdb607d7b75bc879..463ba2669cea55194e2be2c26d02af75dde8d145 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -424,7 +424,6 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct device *dev = &cxled->cxld.dev; - int rc; switch (mode) { case CXL_DECODER_RAM: @@ -435,11 +434,9 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, return -EINVAL; } - down_write(&cxl_dpa_rwsem); - if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) { - rc = -EBUSY; - goto out; - } + guard(rwsem_write)(&cxl_dpa_rwsem); + if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) + return -EBUSY; /* * Only allow modes that are supported by the current partition @@ -447,21 +444,15 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, */ if (mode == CXL_DECODER_PMEM && !resource_size(&cxlds->pmem_res)) { dev_dbg(dev, "no available pmem capacity\n"); - rc = -ENXIO; - goto out; + return -ENXIO; } if (mode == CXL_DECODER_RAM && !resource_size(&cxlds->ram_res)) { dev_dbg(dev, "no available ram capacity\n"); - rc = -ENXIO; - goto out; + return -ENXIO; } cxled->mode = mode; - rc = 0; -out: - up_write(&cxl_dpa_rwsem); - - return rc; + return 0; } int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size) From patchwork Thu Nov 7 20:58:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867137 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 20AFA21A4CB; Thu, 7 Nov 2024 20:58:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013124; cv=none; b=jIw23KifieBxcusjmeMXyTvXzywU24MQ+TEANu4wANS1wwMH07zAJqC+td3B39m5nDEarv3hr2gn4qb7c5eHehYhXzfBAMd1BJ/rzwS/1UlURR987j//AJ7Ugb9/hUfAOiefGzWq+AY/+6RfcBIAJ404jg/8Y3E6hXO8tCmmbq0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013124; c=relaxed/simple; bh=75BXQWBlu1qm/IwTqsytAV/le/RP7NEqiwLIaFQMfE0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Kxlq2SX+cYURsBDUmRaqrFNc7sXkDOFxUYCvxV4ebAAZL+8t1LW9oC98AufkL59WipT7AH1Tfy87qoY6zNHHgEccVxma3BjgOVx835V0tzy31SYFYPYimlLeWgfZcJh7CHdBrjYftPkoas4kejp2L6r7FZ8tUZzxA3GpqoPxgW0= 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=gqVgx1dS; arc=none smtp.client-ip=192.198.163.18 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="gqVgx1dS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013123; x=1762549123; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=75BXQWBlu1qm/IwTqsytAV/le/RP7NEqiwLIaFQMfE0=; b=gqVgx1dSF24W1Wd4BziQiyQ6ifF25qWdAg049iIX9THRlTsmf5Jhpcys 0KtJE4DnCxoKs893m6UfnUaxJhwiL9sKaQM9YZDbOyOrTTqD9P13hdA0J QTDhapy+sj6vu+O7coRK1/oJ3TuFBkM9WUCLQKE3GTucsy4zy0GHCQ91/ tetEY3VYFKAedHD6CHX+hfwqG/tHb3EDZ/E4asTiyOOTu0B+emMJXl8BE X5h7Iwj3cE06iVjjTfxjElQsz7J8sEbsVF04cUaxz4/QmoMzc+BRsI5AG SoKe2kcAWarZ1q/QQ79JGsBJqS3wvfByZnuJFjvIz8YDgq0GbktNqDz5K A==; X-CSE-ConnectionGUID: SfFWxB+DT2+X5TM+hNTJJw== X-CSE-MsgGUID: zfeNjbeySdCzsYr03QyjOw== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300357" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300357" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:43 -0800 X-CSE-ConnectionGUID: hoFw0JLpSWC846B5sSAceg== X-CSE-MsgGUID: rMAG5OAnT4qyR3PChUGXxQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093617" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:41 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:24 -0600 Subject: [PATCH v7 06/27] cxl/region: Refactor common create region code Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-6-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=2691; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=75BXQWBlu1qm/IwTqsytAV/le/RP7NEqiwLIaFQMfE0=; b=P5NFy810p+Mcoo9NX+SKYo309XX3Xmjk7p3ymUd6Quv56QnFprfYx05IGG0bGmqF24M1raZdI BKEtUDiNSOyBaedgIm/4KPvJD6X2etX62hn8Vc8XOSEOCsV2uzyt3Tj X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= create_pmem_region_store() and create_ram_region_store() are identical with the exception of the region mode. With the addition of DC region mode this would end up being 3 copies of the same code. Refactor create_pmem_region_store() and create_ram_region_store() to use a single common function to be used in subsequent DC code. Suggested-by: Fan Ni Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Li Ming Reviewed-by: Alison Schofield Signed-off-by: Ira Weiny --- drivers/cxl/core/region.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index e701e4b0403282a06bccfbca6bf212fd35e3a64c..02437e716b7e04493bb7a2b7d14649a2414c1cb7 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2536,9 +2536,8 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, return devm_cxl_add_region(cxlrd, id, mode, CXL_DECODER_HOSTONLYMEM); } -static ssize_t create_pmem_region_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t create_region_store(struct device *dev, const char *buf, + size_t len, enum cxl_decoder_mode mode) { struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); struct cxl_region *cxlr; @@ -2548,31 +2547,26 @@ static ssize_t create_pmem_region_store(struct device *dev, if (rc != 1) return -EINVAL; - cxlr = __create_region(cxlrd, CXL_DECODER_PMEM, id); + cxlr = __create_region(cxlrd, mode, id); if (IS_ERR(cxlr)) return PTR_ERR(cxlr); return len; } + +static ssize_t create_pmem_region_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return create_region_store(dev, buf, len, CXL_DECODER_PMEM); +} DEVICE_ATTR_RW(create_pmem_region); static ssize_t create_ram_region_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); - struct cxl_region *cxlr; - int rc, id; - - rc = sscanf(buf, "region%d\n", &id); - if (rc != 1) - return -EINVAL; - - cxlr = __create_region(cxlrd, CXL_DECODER_RAM, id); - if (IS_ERR(cxlr)) - return PTR_ERR(cxlr); - - return len; + return create_region_store(dev, buf, len, CXL_DECODER_RAM); } DEVICE_ATTR_RW(create_ram_region); From patchwork Thu Nov 7 20:58:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867138 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 D3FD721A6F9; Thu, 7 Nov 2024 20:58:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013127; cv=none; b=qNXzFort4cYQWsaNZIqlvPu90KXthNqTqI+fVbxJzvyx99hGruufDSa0iLP3FTX0g2fDIvANkDiLmJqybBN8MO6uACnoPtjrXMeYkdbH3ESm7PA+fAIekT2F1nzybzZ9yVqfsSRgYXjHWRemNftSR31Y1zSZFLClC+5J3wj5SGc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013127; c=relaxed/simple; bh=JoHlfcxAJftVbYk8BRgv0BTrjQVm0Kl9TKT0u5ElTVo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=V+CuFmS8GTp/5vp6jWXNQ8LbBmg/cR5BniX5vREcB3nMX9wAMoHbyB7uIDFISwiB5+zGqe9AjLu87yQkSX1DGvgypr5zaHv1S96lbhLxIxZF+u2tORWTjmnES83ZLsrwjtFjgB/MXpfOV9QsGFZ2vqPJdb0KdMXa/B6LlvWu5+M= 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=QTiRVtuM; arc=none smtp.client-ip=192.198.163.18 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="QTiRVtuM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013126; x=1762549126; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=JoHlfcxAJftVbYk8BRgv0BTrjQVm0Kl9TKT0u5ElTVo=; b=QTiRVtuMz6TCmOvLBVCHbm8BzjTdoXKXDTLWmkEH5m0phnMatlGUHl9S 1H9TrJktKBjo3QPZtGOLeMpzw8RCcDTPt73qN2m+KElY+eDnFeast/PVR 5BTYZDCG1YSTSVny9B+hXjhLxKtm1AS9jdeCsNFSpTzN22mf5QwkggNKE /YA572Wkm6m4+bbiXvWWKRPXVyy2nfVeR+TAYqHttsyP5DdC6IVK98Tc+ meyXenWQCKuvq4uTSgcjdQh908JIDRvjrXCZYtU4i8gA8f1pvvKdC+KhW UEmVW34VvRuwfasVD9HW0pFfr2NjfMXAwD3iRMVuNzYHimmSWJKX8eP2R w==; X-CSE-ConnectionGUID: YddP1uXJT2meADML/Ed9cw== X-CSE-MsgGUID: 8CjWeP/JQ/iWtY1f6W2yrg== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300364" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300364" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:45 -0800 X-CSE-ConnectionGUID: 3cQTqJh7Q+CV3uW7kPWVfA== X-CSE-MsgGUID: 4csBbNrEQsi4L0y6YWeZig== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093622" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:44 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:25 -0600 Subject: [PATCH v7 07/27] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-7-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=4110; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=aSCfDRIC6e3FEZwRSJpd4dHA/NNKjjYvtAtyGCqpz4Y=; b=+cSLJ1JTCHwg7GPXrWwpL0lvk1zfEhTfnuntf+uZC63PlkCFTkJWbz+wl8gEy18GwIdAEBP9h bb07X0/T/dPCspdnS8UOePeKhgVSHrO+arkLKlT7AOtGUw1pp5EHrOu X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Per the CXL 3.1 specification software must check the Command Effects Log (CEL) for dynamic capacity command support. Detect support for the DCD commands while reading the CEL, including: Get DC Config Get DC Extent List Add DC Response Release DC Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Davidlohr Bueso Reviewed-by: Li Ming Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/mbox.c | 33 +++++++++++++++++++++++++++++++++ drivers/cxl/cxlmem.h | 15 +++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 5175138c4fb7382426145640d7d04967b02b22dc..aac3bfc0d2c3f916dd870b9f8288b24d90fc9974 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -164,6 +164,34 @@ static void cxl_set_security_cmd_enabled(struct cxl_security_state *security, } } +static bool cxl_is_dcd_command(u16 opcode) +{ +#define CXL_MBOX_OP_DCD_CMDS 0x48 + + return (opcode >> 8) == CXL_MBOX_OP_DCD_CMDS; +} + +static void cxl_set_dcd_cmd_enabled(struct cxl_memdev_state *mds, + u16 opcode) +{ + switch (opcode) { + case CXL_MBOX_OP_GET_DC_CONFIG: + set_bit(CXL_DCD_ENABLED_GET_CONFIG, mds->dcd_cmds); + break; + case CXL_MBOX_OP_GET_DC_EXTENT_LIST: + set_bit(CXL_DCD_ENABLED_GET_EXTENT_LIST, mds->dcd_cmds); + break; + case CXL_MBOX_OP_ADD_DC_RESPONSE: + set_bit(CXL_DCD_ENABLED_ADD_RESPONSE, mds->dcd_cmds); + break; + case CXL_MBOX_OP_RELEASE_DC: + set_bit(CXL_DCD_ENABLED_RELEASE, mds->dcd_cmds); + break; + default: + break; + } +} + static bool cxl_is_poison_command(u16 opcode) { #define CXL_MBOX_OP_POISON_CMDS 0x43 @@ -751,6 +779,11 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) enabled++; } + if (cxl_is_dcd_command(opcode)) { + cxl_set_dcd_cmd_enabled(mds, opcode); + enabled++; + } + dev_dbg(dev, "Opcode 0x%04x %s\n", opcode, enabled ? "enabled" : "unsupported by driver"); } diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 2a25d1957ddb9772b8d4dca92534ba76a909f8b3..e8907c403edbd83c8a36b8d013c6bc3391207ee6 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -239,6 +239,15 @@ struct cxl_event_state { struct mutex log_lock; }; +/* Device enabled DCD commands */ +enum dcd_cmd_enabled_bits { + CXL_DCD_ENABLED_GET_CONFIG, + CXL_DCD_ENABLED_GET_EXTENT_LIST, + CXL_DCD_ENABLED_ADD_RESPONSE, + CXL_DCD_ENABLED_RELEASE, + CXL_DCD_ENABLED_MAX +}; + /* Device enabled poison commands */ enum poison_cmd_enabled_bits { CXL_POISON_ENABLED_LIST, @@ -461,6 +470,7 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox) * @lsa_size: Size of Label Storage Area * (CXL 2.0 8.2.9.5.1.1 Identify Memory Device) * @firmware_version: Firmware version for the memory device. + * @dcd_cmds: List of DCD commands implemented by memory device * @enabled_cmds: Hardware commands found enabled in CEL. * @exclusive_cmds: Commands that are kernel-internal only * @total_bytes: sum of all possible capacities @@ -485,6 +495,7 @@ struct cxl_memdev_state { struct cxl_dev_state cxlds; size_t lsa_size; char firmware_version[0x10]; + DECLARE_BITMAP(dcd_cmds, CXL_DCD_ENABLED_MAX); DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); u64 total_bytes; @@ -554,6 +565,10 @@ enum cxl_opcode { CXL_MBOX_OP_UNLOCK = 0x4503, CXL_MBOX_OP_FREEZE_SECURITY = 0x4504, CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE = 0x4505, + CXL_MBOX_OP_GET_DC_CONFIG = 0x4800, + CXL_MBOX_OP_GET_DC_EXTENT_LIST = 0x4801, + CXL_MBOX_OP_ADD_DC_RESPONSE = 0x4802, + CXL_MBOX_OP_RELEASE_DC = 0x4803, CXL_MBOX_OP_MAX = 0x10000 }; From patchwork Thu Nov 7 20:58:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867139 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) (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 67367218930; Thu, 7 Nov 2024 20:58:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013130; cv=none; b=ovErrGBQK0ECuxOne084R0DftamQL0fy3Fss/pf7/m7lpt/v0QXVVz0jgzBy6Wxxdmy6JuaLD/xj8zS+bippGn+Yq0mWokTb2EevDErMbwVkjk1PviaaZkZcGaZBIWOi+BYGya4XmV6PEvsc/DLF1dS3Q3CXcbfurilAHT8t5TM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013130; c=relaxed/simple; bh=lMv8bmlpHA1FGB5LZAblsyfifVr5OcjLjITEIivtIwg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=B37wZYajqPGOIwmariSqNfZX7bUmMhA0vvmofgWJ8/qIduC1TCN+TucrBxXCOoqouqj2Bmr43FCMjQQ7dLds3V8uHG8WA/tBqC5Q4AixArfW2NBEKHDF4c7gvxOUBOvksXJalMGquy62Atzve9dgEjwTHchPqpmofhT6K1WkHYU= 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=ZtcNLGY9; arc=none smtp.client-ip=192.198.163.18 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="ZtcNLGY9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013128; x=1762549128; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=lMv8bmlpHA1FGB5LZAblsyfifVr5OcjLjITEIivtIwg=; b=ZtcNLGY9LenWtmnG7He3eEVZ4fKGDy5OqICUlzwq3rJXh8wzSWR0dAcG RYIRRucC6LoS+snfKO7+hZrgMKI9w6WAEDlPq5h3NyDBkfRjQ/m3mAeSJ W/sO/l3IV+Z0L/BjEJJ68C9jCmMGAENJk3wV2mMG3i66Q1EH6jecYOLrK AslS5qREWXuyL97ZVdTlToCClMDXMlwZYI2WXtbSD0htF/nISL8hX7tax l+8ITd/7KmfckOKqw+KZPPzaU2AqfpvmLAsv/j8R2YNOOgKlNMcj94zjc /LewRQJ/H1oAkJC47k2+ZEwvXgWFiu96KAqguzQGNyJO6ps0ITAl888rF g==; X-CSE-ConnectionGUID: a/2VMrd0SVqZbSFrSJwbeQ== X-CSE-MsgGUID: eiM3xoEZTHWJAlWbr31ipQ== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="30300373" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="30300373" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:48 -0800 X-CSE-ConnectionGUID: uZUo7I6XQe+ctCjAud/qWQ== X-CSE-MsgGUID: BcmHpZ50S8iUe2zvWTpKNQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="90093629" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:46 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:26 -0600 Subject: [PATCH v7 08/27] cxl/mem: Read dynamic capacity configuration from the device Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-8-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Kees Cook , "Gustavo A. R. Silva" , linux-hardening@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=14041; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=imEV0qrXrqUc/0FzLd1IORH6AtTKFZI0aFEj8VEXe08=; b=ClnSgAm+veX7IkOyOB3uGfEQLFmVI2WH7VDV5wJ29mEZc8p68H40Haje0XPO1jBAeKU+92kQY gEWCMZH+0dZDqTj/SHmZ3nTVA0ZW1O/5bxfTlkQT29PIxSH+JoXmU0a X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Devices which optionally support Dynamic Capacity (DC) are configured via mailbox commands. CXL 3.1 requires the host to issue the Get DC Configuration command in order to properly configure DCDs. Without the Get DC Configuration command DCD can't be supported. Implement the DC mailbox commands as specified in CXL 3.1 section 8.2.9.9.9 (opcodes 48XXh) to read and store the DCD configuration information. Disable DCD if DCD is not supported. Leverage the Get DC Configuration command supported bit to indicate if DCD is supported. Linux has no use for the trailing fields of the Get Dynamic Capacity Configuration Output Payload (Total number of supported extents, number of available extents, total number of supported tags, and number of available tags). Avoid defining those fields to use the more useful dynamic C array. Cc: Li, Ming Cc: Kees Cook Cc: Gustavo A. R. Silva Cc: linux-hardening@vger.kernel.org Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/mbox.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++- drivers/cxl/cxlmem.h | 64 ++++++++++++++++++- drivers/cxl/pci.c | 4 ++ 3 files changed, 232 insertions(+), 2 deletions(-) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index aac3bfc0d2c3f916dd870b9f8288b24d90fc9974..2c9a9af3dde3a294cde628880066b514b870029f 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1168,7 +1168,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds) if (rc < 0) return rc; - mds->total_bytes = + mds->static_bytes = le64_to_cpu(id.total_capacity) * CXL_CAPACITY_MULTIPLIER; mds->volatile_only_bytes = le64_to_cpu(id.volatile_capacity) * CXL_CAPACITY_MULTIPLIER; @@ -1274,6 +1274,154 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd) return rc; } +static int cxl_dc_save_region_info(struct cxl_memdev_state *mds, u8 index, + struct cxl_dc_region_config *region_config) +{ + struct cxl_dc_region_info *dcr = &mds->dc_region[index]; + struct device *dev = mds->cxlds.dev; + + dcr->base = le64_to_cpu(region_config->region_base); + dcr->decode_len = le64_to_cpu(region_config->region_decode_length); + dcr->decode_len *= CXL_CAPACITY_MULTIPLIER; + dcr->len = le64_to_cpu(region_config->region_length); + dcr->blk_size = le64_to_cpu(region_config->region_block_size); + dcr->dsmad_handle = le32_to_cpu(region_config->region_dsmad_handle); + dcr->flags = region_config->flags; + snprintf(dcr->name, CXL_DC_REGION_STRLEN, "dc%d", index); + + /* Check regions are in increasing DPA order */ + if (index > 0) { + struct cxl_dc_region_info *prev_dcr = &mds->dc_region[index - 1]; + + if ((prev_dcr->base + prev_dcr->decode_len) > dcr->base) { + dev_err(dev, + "DPA ordering violation for DC region %d and %d\n", + index - 1, index); + return -EINVAL; + } + } + + if (!IS_ALIGNED(dcr->base, SZ_256M) || + !IS_ALIGNED(dcr->base, dcr->blk_size)) { + dev_err(dev, "DC region %d invalid base %#llx blk size %#llx\n", + index, dcr->base, dcr->blk_size); + return -EINVAL; + } + + if (dcr->decode_len == 0 || dcr->len == 0 || dcr->decode_len < dcr->len || + !IS_ALIGNED(dcr->len, dcr->blk_size)) { + dev_err(dev, "DC region %d invalid length; decode %#llx len %#llx blk size %#llx\n", + index, dcr->decode_len, dcr->len, dcr->blk_size); + return -EINVAL; + } + + if (dcr->blk_size == 0 || dcr->blk_size % CXL_DCD_BLOCK_LINE_SIZE || + !is_power_of_2(dcr->blk_size)) { + dev_err(dev, "DC region %d invalid block size; %#llx\n", + index, dcr->blk_size); + return -EINVAL; + } + + dev_dbg(dev, + "DC region %s base %#llx length %#llx block size %#llx\n", + dcr->name, dcr->base, dcr->decode_len, dcr->blk_size); + + return 0; +} + +/* Returns the number of regions in dc_resp or -ERRNO */ +static int cxl_get_dc_config(struct cxl_memdev_state *mds, u8 start_region, + struct cxl_mbox_get_dc_config_out *dc_resp, + size_t dc_resp_size) +{ + struct cxl_mbox_get_dc_config_in get_dc = (struct cxl_mbox_get_dc_config_in) { + .region_count = CXL_MAX_DC_REGION, + .start_region_index = start_region, + }; + struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_DC_CONFIG, + .payload_in = &get_dc, + .size_in = sizeof(get_dc), + .size_out = dc_resp_size, + .payload_out = dc_resp, + .min_out = 1, + }; + struct device *dev = mds->cxlds.dev; + int rc; + + rc = cxl_internal_send_cmd(&mds->cxlds.cxl_mbox, &mbox_cmd); + if (rc < 0) + return rc; + + dev_dbg(dev, "Read %d/%d DC regions\n", + dc_resp->regions_returned, dc_resp->avail_region_count); + return dc_resp->regions_returned; +} + +/** + * cxl_dev_dynamic_capacity_identify() - Reads the dynamic capacity + * information from the device. + * @mds: The memory device state + * + * Read Dynamic Capacity information from the device and populate the state + * structures for later use. + * + * Return: 0 if identify was executed successfully, -ERRNO on error. + */ +int cxl_dev_dynamic_capacity_identify(struct cxl_memdev_state *mds) +{ + size_t dc_resp_size = mds->cxlds.cxl_mbox.payload_size; + struct device *dev = mds->cxlds.dev; + u8 start_region, i; + + if (!cxl_dcd_supported(mds)) { + dev_dbg(dev, "DCD not supported\n"); + return 0; + } + + struct cxl_mbox_get_dc_config_out *dc_resp __free(kfree) = + kvmalloc(dc_resp_size, GFP_KERNEL); + if (!dc_resp) + return -ENOMEM; + + start_region = 0; + do { + int rc, j; + + rc = cxl_get_dc_config(mds, start_region, dc_resp, dc_resp_size); + if (rc < 0) { + dev_err(dev, "Failed to get DC config: %d\n", rc); + return rc; + } + + mds->nr_dc_region += rc; + + if (mds->nr_dc_region < 1 || mds->nr_dc_region > CXL_MAX_DC_REGION) { + dev_err(dev, "Invalid num of dynamic capacity regions %d\n", + mds->nr_dc_region); + return -EINVAL; + } + + for (i = start_region, j = 0; i < mds->nr_dc_region; i++, j++) { + rc = cxl_dc_save_region_info(mds, i, &dc_resp->region[j]); + if (rc) + return rc; + } + + start_region = mds->nr_dc_region; + + } while (mds->nr_dc_region < dc_resp->avail_region_count); + + mds->dynamic_bytes = + mds->dc_region[mds->nr_dc_region - 1].base + + mds->dc_region[mds->nr_dc_region - 1].decode_len - + mds->dc_region[0].base; + dev_dbg(dev, "Total dynamic range: %#llx\n", mds->dynamic_bytes); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_dev_dynamic_capacity_identify, CXL); + static int add_dpa_res(struct device *dev, struct resource *parent, struct resource *res, resource_size_t start, resource_size_t size, const char *type) @@ -1304,8 +1452,15 @@ int cxl_mem_create_range_info(struct cxl_memdev_state *mds) { struct cxl_dev_state *cxlds = &mds->cxlds; struct device *dev = cxlds->dev; + size_t untenanted_mem; int rc; + mds->total_bytes = mds->static_bytes; + if (mds->nr_dc_region) { + untenanted_mem = mds->dc_region[0].base - mds->static_bytes; + mds->total_bytes += untenanted_mem + mds->dynamic_bytes; + } + if (!cxlds->media_ready) { cxlds->dpa_res = DEFINE_RES_MEM(0, 0); cxlds->ram_res = DEFINE_RES_MEM(0, 0); @@ -1315,6 +1470,15 @@ int cxl_mem_create_range_info(struct cxl_memdev_state *mds) cxlds->dpa_res = DEFINE_RES_MEM(0, mds->total_bytes); + for (int i = 0; i < mds->nr_dc_region; i++) { + struct cxl_dc_region_info *dcr = &mds->dc_region[i]; + + rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->dc_res[i], + dcr->base, dcr->decode_len, dcr->name); + if (rc) + return rc; + } + if (mds->partition_align_bytes == 0) { rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0, mds->volatile_only_bytes, "ram"); diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index e8907c403edbd83c8a36b8d013c6bc3391207ee6..05a0718aea73b3b2a02c608bae198eac7c462523 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -403,6 +403,7 @@ enum cxl_devtype { CXL_DEVTYPE_CLASSMEM, }; +#define CXL_MAX_DC_REGION 8 /** * struct cxl_dpa_perf - DPA performance property entry * @dpa_range: range for DPA address @@ -434,6 +435,8 @@ struct cxl_dpa_perf { * @dpa_res: Overall DPA resource tree for the device * @pmem_res: Active Persistent memory capacity configuration * @ram_res: Active Volatile memory capacity configuration + * @dc_res: Active Dynamic Capacity memory configuration for each possible + * region * @serial: PCIe Device Serial Number * @type: Generic Memory Class device or Vendor Specific Memory device * @cxl_mbox: CXL mailbox context @@ -449,11 +452,23 @@ struct cxl_dev_state { struct resource dpa_res; struct resource pmem_res; struct resource ram_res; + struct resource dc_res[CXL_MAX_DC_REGION]; u64 serial; enum cxl_devtype type; struct cxl_mailbox cxl_mbox; }; +#define CXL_DC_REGION_STRLEN 8 +struct cxl_dc_region_info { + u64 base; + u64 decode_len; + u64 len; + u64 blk_size; + u32 dsmad_handle; + u8 flags; + u8 name[CXL_DC_REGION_STRLEN]; +}; + static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox) { return dev_get_drvdata(cxl_mbox->host); @@ -473,7 +488,9 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox) * @dcd_cmds: List of DCD commands implemented by memory device * @enabled_cmds: Hardware commands found enabled in CEL. * @exclusive_cmds: Commands that are kernel-internal only - * @total_bytes: sum of all possible capacities + * @total_bytes: length of all possible capacities + * @static_bytes: length of possible static RAM and PMEM partitions + * @dynamic_bytes: length of possible DC partitions (DC Regions) * @volatile_only_bytes: hard volatile capacity * @persistent_only_bytes: hard persistent capacity * @partition_align_bytes: alignment size for partition-able capacity @@ -483,6 +500,8 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox) * @next_persistent_bytes: persistent capacity change pending device reset * @ram_perf: performance data entry matched to RAM partition * @pmem_perf: performance data entry matched to PMEM partition + * @nr_dc_region: number of DC regions implemented in the memory device + * @dc_region: array containing info about the DC regions * @event: event log driver state * @poison: poison driver state info * @security: security driver state info @@ -499,6 +518,8 @@ struct cxl_memdev_state { DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); u64 total_bytes; + u64 static_bytes; + u64 dynamic_bytes; u64 volatile_only_bytes; u64 persistent_only_bytes; u64 partition_align_bytes; @@ -510,6 +531,9 @@ struct cxl_memdev_state { struct cxl_dpa_perf ram_perf; struct cxl_dpa_perf pmem_perf; + u8 nr_dc_region; + struct cxl_dc_region_info dc_region[CXL_MAX_DC_REGION]; + struct cxl_event_state event; struct cxl_poison_state poison; struct cxl_security_state security; @@ -708,6 +732,32 @@ struct cxl_mbox_set_partition_info { #define CXL_SET_PARTITION_IMMEDIATE_FLAG BIT(0) +/* See CXL 3.1 Table 8-163 get dynamic capacity config Input Payload */ +struct cxl_mbox_get_dc_config_in { + u8 region_count; + u8 start_region_index; +} __packed; + +/* See CXL 3.1 Table 8-164 get dynamic capacity config Output Payload */ +struct cxl_mbox_get_dc_config_out { + u8 avail_region_count; + u8 regions_returned; + u8 rsvd[6]; + /* See CXL 3.1 Table 8-165 */ + struct cxl_dc_region_config { + __le64 region_base; + __le64 region_decode_length; + __le64 region_length; + __le64 region_block_size; + __le32 region_dsmad_handle; + u8 flags; + u8 rsvd[3]; + } __packed region[] __counted_by(regions_returned); + /* Trailing fields unused */ +} __packed; +#define CXL_DYNAMIC_CAPACITY_SANITIZE_ON_RELEASE_FLAG BIT(0) +#define CXL_DCD_BLOCK_LINE_SIZE 0x40 + /* Set Timestamp CXL 3.0 Spec 8.2.9.4.2 */ struct cxl_mbox_set_timestamp_in { __le64 timestamp; @@ -831,6 +881,7 @@ enum { int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *cmd); int cxl_dev_state_identify(struct cxl_memdev_state *mds); +int cxl_dev_dynamic_capacity_identify(struct cxl_memdev_state *mds); int cxl_await_media_ready(struct cxl_dev_state *cxlds); int cxl_enumerate_cmds(struct cxl_memdev_state *mds); int cxl_mem_create_range_info(struct cxl_memdev_state *mds); @@ -844,6 +895,17 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, enum cxl_event_type event_type, const uuid_t *uuid, union cxl_event *evt); + +static inline bool cxl_dcd_supported(struct cxl_memdev_state *mds) +{ + return test_bit(CXL_DCD_ENABLED_GET_CONFIG, mds->dcd_cmds); +} + +static inline void cxl_disable_dcd(struct cxl_memdev_state *mds) +{ + clear_bit(CXL_DCD_ENABLED_GET_CONFIG, mds->dcd_cmds); +} + int cxl_set_timestamp(struct cxl_memdev_state *mds); int cxl_poison_state_init(struct cxl_memdev_state *mds); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 295779c433b2a2e377995b53a70ff2a3158b0a8e..c8454b3ecea5c053bf9723c275652398c0b2a195 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -899,6 +899,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; + rc = cxl_dev_dynamic_capacity_identify(mds); + if (rc) + cxl_disable_dcd(mds); + rc = cxl_mem_create_range_info(mds); if (rc) return rc; From patchwork Thu Nov 7 20:58:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867140 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 B3753322E; Thu, 7 Nov 2024 20:58:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013132; cv=none; b=CGIcE08MhqEEgQSZqqzWThLC2oQCd5Encsqrql9xw27MIvdo3NYHlg6UY3hSXYmF68WEJX1g7YAm4x5GfyOwg8OGczTCaGfcns8vNs86AMF9+/a9Y/i4rw1N28VDAoqKaAcH63RY04tWZFfpNoYCy7pSrEvoFMUYqbFxU66EESU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013132; c=relaxed/simple; bh=mP/39uB6KFgSJCccrYcbJwHbhU4pRB9iVaDNiG2eUEc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eXJinxrRWDLFFKXtXfpSqG4b7kdEsJcrn5EiUGii9/q+RxY16sLGkX+FhLg33EvS6M9v27TfplztL60RKTlCsE/EGXzKr0LCZxo7N1bN4ycn3LlxZ2jCmVgs4HFHVz+bMboS8LF8GY/LcYCPP69rLqP/Z2K8X0T6egfz7K3Nr1w= 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=DKABXUZl; arc=none smtp.client-ip=198.175.65.11 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="DKABXUZl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013131; x=1762549131; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=mP/39uB6KFgSJCccrYcbJwHbhU4pRB9iVaDNiG2eUEc=; b=DKABXUZljbOKYORfOipNfNcxuOn0C5GUQ0OLmviYsZwIB2nH+bnB5aSX aYHgku69KYwwaHLTKmwxlySe8/UuR19xuHY6WC4uY8khOt1v927f5oIPn qckyzg6nzywJAvpkuEwIUSkIEGFY0uefXzUsrUrYwxkZw8fHXKVpUDvIR wQkt54VWWjAmKFSfLg9LZYvZTG9kBOFgAVB/g8BUswq17HFyAtnwysGiW zY0vQ9X56LR6Kcz+r3Ux9eA8dA2/WZVNCjfuqgmUDfZJtaOn9mKOwLt3I IJDyS0xslN2kFrZCKUFgggHiiCRaTPz37xyxDBpnI7+XDHmvpCN7wjfcn A==; X-CSE-ConnectionGUID: MjHO8OnSTpuSpfaVJ9VIPQ== X-CSE-MsgGUID: fo2lRnoXREWECPpB0Bq2qQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41440990" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41440990" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:50 -0800 X-CSE-ConnectionGUID: 4OIGDRDwQ6+rZQBfQxRvDA== X-CSE-MsgGUID: ZabFLpwESY2qQ+uMAipGaQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122745966" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:49 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:27 -0600 Subject: [PATCH v7 09/27] cxl/core: Separate region mode from decoder mode Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-9-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Jonathan Cameron , Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=11182; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=VIK7W0grb8am/P99hC4l92sVeGLL2N2lFNNyt2pqocQ=; b=BukvqYgzmGlAbB65ljUXpRIlXYfBuyQmrLxBpkCVfcdrzK1fbqGwl8Pe3oQjhAX6kss2OxsSP pbus6cHglmiA7BYxu0Wmjl08ESSw980MN0Gynry4S8krmKuwqwpbsQ7 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Until now region modes and decoder modes were equivalent in that both modes were either PMEM or RAM. The addition of Dynamic Capacity partitions defines up to 8 DC partitions per device. The region mode is thus no longer equivalent to the endpoint decoder mode. IOW the endpoint decoders may have modes of DC0-DC7 while the region mode is simply DC. Define a new region mode enumeration which applies to regions separate from the decoder mode. Adjust the code to process these modes independently. There is no equal to decoder mode dead in region modes. Avoid constructing regions with decoders which have been flagged as dead. Suggested-by: Jonathan Cameron Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Li Ming Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/cdat.c | 6 ++-- drivers/cxl/core/region.c | 77 ++++++++++++++++++++++++++++++++++------------- drivers/cxl/cxl.h | 26 ++++++++++++++-- 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index ef1621d40f0542e85b01f243f888cd0368111885..b5d30c5bf1e20725d13b4397a7ba90662bcd8766 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -571,17 +571,17 @@ static bool dpa_perf_contains(struct cxl_dpa_perf *perf, } static struct cxl_dpa_perf *cxled_get_dpa_perf(struct cxl_endpoint_decoder *cxled, - enum cxl_decoder_mode mode) + enum cxl_region_mode mode) { struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); struct cxl_dpa_perf *perf; switch (mode) { - case CXL_DECODER_RAM: + case CXL_REGION_RAM: perf = &mds->ram_perf; break; - case CXL_DECODER_PMEM: + case CXL_REGION_PMEM: perf = &mds->pmem_perf; break; default: diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 02437e716b7e04493bb7a2b7d14649a2414c1cb7..b3beab787faeb552850ac3839472319fcf8f2835 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -144,7 +144,7 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, rc = down_read_interruptible(&cxl_region_rwsem); if (rc) return rc; - if (cxlr->mode != CXL_DECODER_PMEM) + if (cxlr->mode != CXL_REGION_PMEM) rc = sysfs_emit(buf, "\n"); else rc = sysfs_emit(buf, "%pUb\n", &p->uuid); @@ -457,7 +457,7 @@ static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a, * Support tooling that expects to find a 'uuid' attribute for all * regions regardless of mode. */ - if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM) + if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_REGION_PMEM) return 0444; return a->mode; } @@ -620,7 +620,7 @@ static ssize_t mode_show(struct device *dev, struct device_attribute *attr, { struct cxl_region *cxlr = to_cxl_region(dev); - return sysfs_emit(buf, "%s\n", cxl_decoder_mode_name(cxlr->mode)); + return sysfs_emit(buf, "%s\n", cxl_region_mode_name(cxlr->mode)); } static DEVICE_ATTR_RO(mode); @@ -646,7 +646,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) /* ways, granularity and uuid (if PMEM) need to be set before HPA */ if (!p->interleave_ways || !p->interleave_granularity || - (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) + (cxlr->mode == CXL_REGION_PMEM && uuid_is_null(&p->uuid))) return -ENXIO; div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder); @@ -1863,6 +1863,17 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr) return rc; } +static bool cxl_modes_compatible(enum cxl_region_mode rmode, + enum cxl_decoder_mode dmode) +{ + if (rmode == CXL_REGION_RAM && dmode == CXL_DECODER_RAM) + return true; + if (rmode == CXL_REGION_PMEM && dmode == CXL_DECODER_PMEM) + return true; + + return false; +} + static int cxl_region_attach(struct cxl_region *cxlr, struct cxl_endpoint_decoder *cxled, int pos) { @@ -1882,9 +1893,11 @@ static int cxl_region_attach(struct cxl_region *cxlr, return rc; } - if (cxled->mode != cxlr->mode) { - dev_dbg(&cxlr->dev, "%s region mode: %d mismatch: %d\n", - dev_name(&cxled->cxld.dev), cxlr->mode, cxled->mode); + if (!cxl_modes_compatible(cxlr->mode, cxled->mode)) { + dev_dbg(&cxlr->dev, "%s region mode: %s mismatch decoder: %s\n", + dev_name(&cxled->cxld.dev), + cxl_region_mode_name(cxlr->mode), + cxl_decoder_mode_name(cxled->mode)); return -EINVAL; } @@ -2446,7 +2459,7 @@ static int cxl_region_calculate_adistance(struct notifier_block *nb, * devm_cxl_add_region - Adds a region to a decoder * @cxlrd: root decoder * @id: memregion id to create, or memregion_free() on failure - * @mode: mode for the endpoint decoders of this region + * @mode: mode of this region * @type: select whether this is an expander or accelerator (type-2 or type-3) * * This is the second step of region initialization. Regions exist within an @@ -2457,7 +2470,7 @@ static int cxl_region_calculate_adistance(struct notifier_block *nb, */ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, int id, - enum cxl_decoder_mode mode, + enum cxl_region_mode mode, enum cxl_decoder_type type) { struct cxl_port *port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent); @@ -2511,16 +2524,17 @@ static ssize_t create_ram_region_show(struct device *dev, } static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, - enum cxl_decoder_mode mode, int id) + enum cxl_region_mode mode, int id) { int rc; switch (mode) { - case CXL_DECODER_RAM: - case CXL_DECODER_PMEM: + case CXL_REGION_RAM: + case CXL_REGION_PMEM: break; default: - dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %d\n", mode); + dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %s\n", + cxl_region_mode_name(mode)); return ERR_PTR(-EINVAL); } @@ -2537,7 +2551,7 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, } static ssize_t create_region_store(struct device *dev, const char *buf, - size_t len, enum cxl_decoder_mode mode) + size_t len, enum cxl_region_mode mode) { struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); struct cxl_region *cxlr; @@ -2558,7 +2572,7 @@ static ssize_t create_pmem_region_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - return create_region_store(dev, buf, len, CXL_DECODER_PMEM); + return create_region_store(dev, buf, len, CXL_REGION_PMEM); } DEVICE_ATTR_RW(create_pmem_region); @@ -2566,7 +2580,7 @@ static ssize_t create_ram_region_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - return create_region_store(dev, buf, len, CXL_DECODER_RAM); + return create_region_store(dev, buf, len, CXL_REGION_RAM); } DEVICE_ATTR_RW(create_ram_region); @@ -3209,6 +3223,22 @@ static int match_region_by_range(struct device *dev, void *data) return rc; } +static enum cxl_region_mode +cxl_decoder_to_region_mode(enum cxl_decoder_mode mode) +{ + switch (mode) { + case CXL_DECODER_NONE: + return CXL_REGION_NONE; + case CXL_DECODER_RAM: + return CXL_REGION_RAM; + case CXL_DECODER_PMEM: + return CXL_REGION_PMEM; + case CXL_DECODER_MIXED: + default: + return CXL_REGION_MIXED; + } +} + /* Establish an empty region covering the given HPA range */ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, struct cxl_endpoint_decoder *cxled) @@ -3217,12 +3247,17 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, struct cxl_port *port = cxlrd_to_port(cxlrd); struct range *hpa = &cxled->cxld.hpa_range; struct cxl_region_params *p; + enum cxl_region_mode mode; struct cxl_region *cxlr; struct resource *res; int rc; + if (cxled->mode == CXL_DECODER_DEAD) + return ERR_PTR(-EINVAL); + + mode = cxl_decoder_to_region_mode(cxled->mode); do { - cxlr = __create_region(cxlrd, cxled->mode, + cxlr = __create_region(cxlrd, mode, atomic_read(&cxlrd->region_id)); } while (IS_ERR(cxlr) && PTR_ERR(cxlr) == -EBUSY); @@ -3425,9 +3460,9 @@ static int cxl_region_probe(struct device *dev) return rc; switch (cxlr->mode) { - case CXL_DECODER_PMEM: + case CXL_REGION_PMEM: return devm_cxl_add_pmem_region(cxlr); - case CXL_DECODER_RAM: + case CXL_REGION_RAM: /* * The region can not be manged by CXL if any portion of * it is already online as 'System RAM' @@ -3439,8 +3474,8 @@ static int cxl_region_probe(struct device *dev) return 0; return devm_cxl_add_dax_region(cxlr); default: - dev_dbg(&cxlr->dev, "unsupported region mode: %d\n", - cxlr->mode); + dev_dbg(&cxlr->dev, "unsupported region mode: %s\n", + cxl_region_mode_name(cxlr->mode)); return -ENXIO; } } diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 0d8b810a51f04de299e88ee8b29136bff11ed93e..5d74eb4ffab3ea2656c8e3c0563b8d7b69d76232 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -388,6 +388,27 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode) return "mixed"; } +enum cxl_region_mode { + CXL_REGION_NONE, + CXL_REGION_RAM, + CXL_REGION_PMEM, + CXL_REGION_MIXED, +}; + +static inline const char *cxl_region_mode_name(enum cxl_region_mode mode) +{ + static const char * const names[] = { + [CXL_REGION_NONE] = "none", + [CXL_REGION_RAM] = "ram", + [CXL_REGION_PMEM] = "pmem", + [CXL_REGION_MIXED] = "mixed", + }; + + if (mode >= CXL_REGION_NONE && mode <= CXL_REGION_MIXED) + return names[mode]; + return "mixed"; +} + /* * Track whether this decoder is reserved for region autodiscovery, or * free for userspace provisioning. @@ -515,7 +536,8 @@ struct cxl_region_params { * struct cxl_region - CXL region * @dev: This region's device * @id: This region's id. Id is globally unique across all regions - * @mode: Endpoint decoder allocation / access mode + * @mode: Region mode which defines which endpoint decoder modes the region is + * compatible with * @type: Endpoint decoder target type * @cxl_nvb: nvdimm bridge for coordinating @cxlr_pmem setup / shutdown * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge @@ -528,7 +550,7 @@ struct cxl_region_params { struct cxl_region { struct device dev; int id; - enum cxl_decoder_mode mode; + enum cxl_region_mode mode; enum cxl_decoder_type type; struct cxl_nvdimm_bridge *cxl_nvb; struct cxl_pmem_region *cxlr_pmem; From patchwork Thu Nov 7 20:58:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867141 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 CFF6C21B452; Thu, 7 Nov 2024 20:58:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013134; cv=none; b=HT6EWEPE7E+dB34HYW4F5qtUQYuXDHbmaJwiENAMN1SNbC6UTheG3IDgCIR2y8d8PkFphzqnO3eJEjqSh7viy1LnbFR7JhlYIfS3HkC3eVKVaxQ8bSjczXLM00FO6ix7EAYP8vi3Pbu0V3hD475rDxo2cpfdA+OQmvvRAbeNpmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013134; c=relaxed/simple; bh=iKXekMnJns1r1l4MIAOtOAM/J89hYV0EkfJDrmoDjyw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qLWak4YVUwWcKlENLNwxVnECjPfUANjQQedBhf9Txbeey/hioUHiW4N0zar3h+Xmc0ZY8NTayxblSJmzktVTNFyFQLwn/kwejbVZOmHuCuWcSqNdS9lqWhlS85s8DU3H513u7utwd1jFGWKHCa+opV8/gD6jjxOt+TKBeHVG8wI= 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=lTTbzILL; arc=none smtp.client-ip=198.175.65.11 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="lTTbzILL" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013133; x=1762549133; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=iKXekMnJns1r1l4MIAOtOAM/J89hYV0EkfJDrmoDjyw=; b=lTTbzILLZCOYHjf3DIvJ0vcTUZN0DXU8WNgp9GIR64IM3Cjmey0Gc0G+ 4oL2khJwaf2jlqgECQThUezKS2xq9KGkq6ED5d/E6IZKXjGTvQl0pY2Re 65YFC+m34MgrXgl18mTqn3p1jeTLUdLBT3AtaApobwnlFrQpN7Sor2QfK af0k4r6S41kbpV+4GAtAXCY0oBC9AuWKwvB1upbySbUP79ILLrElYB8AP 12K/CV2JW+mEOGz6Fr4GWrqhQny/aNjGMIKwwEviakcwuPHwqnqSK031y iLdAvCcrBLawEgFoao6AhFZwrmdaayZX6r3iXPpAaXkOsih8+hRr3t+3H w==; X-CSE-ConnectionGUID: dH9/APxgTOevRaxlNCHJjQ== X-CSE-MsgGUID: B2X1iLZ8SBWc5R2py4+l3A== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41440997" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41440997" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:52 -0800 X-CSE-ConnectionGUID: phfWLpxQTU+VtcHdcqb3zw== X-CSE-MsgGUID: mZMEyibeREKILnYQTEbAlA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122745997" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:51 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:28 -0600 Subject: [PATCH v7 10/27] cxl/region: Add dynamic capacity decoder and region modes Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-10-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=3535; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=92oV6LOz1B7q9oFrHHDLBvhNO1dz+h3J4p0UZ4tMspw=; b=bm69Txz7OvoU0AeJo1Seg7enjh3GGYcq8gGWWkdVObqNsO9ShDqJAdltazxinDU31E2pGO4G3 xkjzVvXRcZwCc2i7CRWJpLe2vTBWDDDuUuzs76dknwQeZqCVc4Vzf2+ X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh One or more decoders each pointing to a Dynamic Capacity (DC) partition form a CXL software region. The region mode reflects composition of that entire software region. Decoder mode reflects a specific DC partition. DC partitions are also known as DC regions per CXL specification v3.1. Define the new modes and helper functions required to make the association between these new modes. Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Li Ming Signed-off-by: Navneet Singh Link: https://lore.kernel.org/all/663922b475e50_d54d72945b@dwillia2-xfh.jf.intel.com.notmuch/ [1] Suggested-by: Dan Williams Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/region.c | 4 ++++ drivers/cxl/cxl.h | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index b3beab787faeb552850ac3839472319fcf8f2835..2ca6148d108cc020bebcb34b09028fa59bb62f02 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1870,6 +1870,8 @@ static bool cxl_modes_compatible(enum cxl_region_mode rmode, return true; if (rmode == CXL_REGION_PMEM && dmode == CXL_DECODER_PMEM) return true; + if (rmode == CXL_REGION_DC && cxl_decoder_mode_is_dc(dmode)) + return true; return false; } @@ -3233,6 +3235,8 @@ cxl_decoder_to_region_mode(enum cxl_decoder_mode mode) return CXL_REGION_RAM; case CXL_DECODER_PMEM: return CXL_REGION_PMEM; + case CXL_DECODER_DC0 ... CXL_DECODER_DC7: + return CXL_REGION_DC; case CXL_DECODER_MIXED: default: return CXL_REGION_MIXED; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 5d74eb4ffab3ea2656c8e3c0563b8d7b69d76232..f931ebdd36d05a8aa758627746f0fa425a5f14fd 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -370,6 +370,14 @@ enum cxl_decoder_mode { CXL_DECODER_NONE, CXL_DECODER_RAM, CXL_DECODER_PMEM, + CXL_DECODER_DC0, + CXL_DECODER_DC1, + CXL_DECODER_DC2, + CXL_DECODER_DC3, + CXL_DECODER_DC4, + CXL_DECODER_DC5, + CXL_DECODER_DC6, + CXL_DECODER_DC7, CXL_DECODER_MIXED, CXL_DECODER_DEAD, }; @@ -380,6 +388,14 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode) [CXL_DECODER_NONE] = "none", [CXL_DECODER_RAM] = "ram", [CXL_DECODER_PMEM] = "pmem", + [CXL_DECODER_DC0] = "dc0", + [CXL_DECODER_DC1] = "dc1", + [CXL_DECODER_DC2] = "dc2", + [CXL_DECODER_DC3] = "dc3", + [CXL_DECODER_DC4] = "dc4", + [CXL_DECODER_DC5] = "dc5", + [CXL_DECODER_DC6] = "dc6", + [CXL_DECODER_DC7] = "dc7", [CXL_DECODER_MIXED] = "mixed", }; @@ -388,10 +404,16 @@ static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode) return "mixed"; } +static inline bool cxl_decoder_mode_is_dc(enum cxl_decoder_mode mode) +{ + return (mode >= CXL_DECODER_DC0 && mode <= CXL_DECODER_DC7); +} + enum cxl_region_mode { CXL_REGION_NONE, CXL_REGION_RAM, CXL_REGION_PMEM, + CXL_REGION_DC, CXL_REGION_MIXED, }; @@ -401,6 +423,7 @@ static inline const char *cxl_region_mode_name(enum cxl_region_mode mode) [CXL_REGION_NONE] = "none", [CXL_REGION_RAM] = "ram", [CXL_REGION_PMEM] = "pmem", + [CXL_REGION_DC] = "dc", [CXL_REGION_MIXED] = "mixed", }; From patchwork Thu Nov 7 20:58:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867142 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 29FB821C175; Thu, 7 Nov 2024 20:58:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013137; cv=none; b=SURxr5IOnIXitoUFKYh7Z6Z1apLt/lI6eqiB257vLvsUWJml1rWhP52ksW8jqjNHlnlsM/ia0DTuOIuUQJfNtsTxJnwTdkJfkSc883Fv6mL3asu2Vhy9satwohIU37g4VtHrwrBaNFLPa04mmO/AJtKwCa+NmTMOm/SbSqkib5Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013137; c=relaxed/simple; bh=xaZiLID+FR+6iFUEWlhX1tAdowq+jiolEda0F0i6oLA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ri5BaSe9bXny2phhN9CEW3SQLxmP5EDv93QQK3ti8yVq9FnJCAKInSXOTAZKZAXGITzZfziabyiI8C+mixAn/qWWlBOvq66vmTegTEBWpZGv2R6sZsfstLJtsac5yMP8AbUteUKo4Fxc6ATlfc+Fz885o76FR3C5u4rxhoW2kmg= 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=EcocPej+; arc=none smtp.client-ip=198.175.65.11 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="EcocPej+" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013135; x=1762549135; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=xaZiLID+FR+6iFUEWlhX1tAdowq+jiolEda0F0i6oLA=; b=EcocPej+tejGNcaCnO5I8OgGaZYBJN0hOTdACnT8odKPIUurpfu/bVPZ ggmYUQB3qW+4yFh/dV0R2ajjMrE1qmgInJMibPQni5bEZPifMu3jlWZkL l8Fn7Wjgvd/IuGtDTIYVRGpYMxoCCRBqlX87wW4cg2mDKQaWTcjVKhCSF BGRUM/O37K6ybYmpAqB7QKR43en3QMlvAUh1G1wI6yQxTOYsG0SquB1Nd 4iQsjq5/07sWD6NwIbz4pKW6vur+6y/gw2SayrfG9DW8RLszCGwe+TTkE JiNsp77/AwXFqHB0Aya4z7rQkXI0mbkhB1M5kCgQP9TtIxF9uXFOqEM26 Q==; X-CSE-ConnectionGUID: M6X11bHLR7+/6WffFikXyw== X-CSE-MsgGUID: FpgEP2rFRh2GNqYuyP2oXg== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441006" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441006" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:54 -0800 X-CSE-ConnectionGUID: 93IAwbQSQTmrHnrhfBjcIw== X-CSE-MsgGUID: DU9pJjqDT9mwWF6HvXgodg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746003" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:54 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:29 -0600 Subject: [PATCH v7 11/27] cxl/hdm: Add dynamic capacity size support to endpoint decoders Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-11-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=13407; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=KI5Ifxvsm3LLB6CwqG0XN7O+ecP50Xawu96QZYBu1o8=; b=aLiDSob+A96t0o+2j05xmOXahHf4sxgvThwMzntbEHY2CquicB3ss/aLOOZNe4x1LgUglUP5I 822MmdvzWQgCIEnuRhhc0Uzzplqs5uzMNS5URBac9oMV9jXlwAfSL40 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh To support Dynamic Capacity Devices (DCD) endpoint decoders will need to map DC partitions (regions). In addition to assigning the size of the DC partition, the decoder must assign any skip value from the previous decoder. This must be done within a contiguous DPA space. Two complications arise with Dynamic Capacity regions which did not exist with Ram and PMEM partitions. First, gaps in the DPA space can exist between and around the DC partitions. Second, the Linux resource tree does not allow a resource to be marked across existing nodes within a tree. For clarity, below is an example of an 60GB device with 10GB of RAM, 10GB of PMEM and 10GB for each of 2 DC partitions. The desired CXL mapping is 5GB of RAM, 5GB of PMEM, and 5GB of DC1. DPA RANGE (dpa_res) 0GB 10GB 20GB 30GB 40GB 50GB 60GB |----------|----------|----------|----------|----------|----------| RAM PMEM DC0 DC1 (ram_res) (pmem_res) (dc_res[0]) (dc_res[1]) |----------|----------| |----------| |----------| RAM PMEM DC1 |XXXXX|----|XXXXX|----|----------|----------|----------|XXXXX-----| 0GB 5GB 10GB 15GB 20GB 30GB 40GB 50GB 60GB The previous skip resource between RAM and PMEM was always a child of the RAM resource and fit nicely [see (S) below]. Because of this simplicity this skip resource reference was not stored in any CXL state. On release the skip range could be calculated based on the endpoint decoders stored values. Now when DC1 is being mapped 4 skip resources must be created as children. One for the PMEM resource (A), two of the parent DPA resource (B,D), and one more child of the DC0 resource (C). 0GB 10GB 20GB 30GB 40GB 50GB 60GB |----------|----------|----------|----------|----------|----------| | | |----------|----------| | |----------| | |----------| | | | | | (S) (A) (B) (C) (D) v v v v v |XXXXX|----|XXXXX|----|----------|----------|----------|XXXXX-----| skip skip skip skip skip Expand the calculation of DPA free space and enhance the logic to support this more complex skipping. To track the potential of multiple skip resources an xarray is attached to the endpoint decoder. The existing algorithm between RAM and PMEM is consolidated within the new one to streamline the code even though the result is the storage of a single skip resource in the xarray. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/hdm.c | 194 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/cxl/core/port.c | 2 + drivers/cxl/cxl.h | 2 + 3 files changed, 182 insertions(+), 16 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 463ba2669cea55194e2be2c26d02af75dde8d145..998aed17d7e47fc18a05fb2e8cca25de0e92a6d4 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -223,6 +223,23 @@ void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds) } EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, CXL); +static void cxl_skip_release(struct cxl_endpoint_decoder *cxled) +{ + struct cxl_dev_state *cxlds = cxled_to_memdev(cxled)->cxlds; + struct cxl_port *port = cxled_to_port(cxled); + struct device *dev = &port->dev; + struct resource *res; + unsigned long index; + + xa_for_each(&cxled->skip_xa, index, res) { + dev_dbg(dev, "decoder%d.%d: releasing skipped space; %pr\n", + port->id, cxled->cxld.id, res); + __release_region(&cxlds->dpa_res, res->start, + resource_size(res)); + xa_erase(&cxled->skip_xa, index); + } +} + /* * Must be called in a context that synchronizes against this decoder's * port ->remove() callback (like an endpoint decoder sysfs attribute) @@ -233,15 +250,11 @@ static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled) struct cxl_port *port = cxled_to_port(cxled); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct resource *res = cxled->dpa_res; - resource_size_t skip_start; lockdep_assert_held_write(&cxl_dpa_rwsem); - /* save @skip_start, before @res is released */ - skip_start = res->start - cxled->skip; __release_region(&cxlds->dpa_res, res->start, resource_size(res)); - if (cxled->skip) - __release_region(&cxlds->dpa_res, skip_start, cxled->skip); + cxl_skip_release(cxled); cxled->skip = 0; cxled->dpa_res = NULL; put_device(&cxled->cxld.dev); @@ -268,6 +281,105 @@ static void devm_cxl_dpa_release(struct cxl_endpoint_decoder *cxled) __cxl_dpa_release(cxled); } +static int dc_mode_to_region_index(enum cxl_decoder_mode mode) +{ + return mode - CXL_DECODER_DC0; +} + +static int cxl_request_skip(struct cxl_endpoint_decoder *cxled, + resource_size_t skip_base, resource_size_t skip_len) +{ + struct cxl_dev_state *cxlds = cxled_to_memdev(cxled)->cxlds; + const char *name = dev_name(&cxled->cxld.dev); + struct cxl_port *port = cxled_to_port(cxled); + struct resource *dpa_res = &cxlds->dpa_res; + struct device *dev = &port->dev; + struct resource *res; + int rc; + + res = __request_region(dpa_res, skip_base, skip_len, name, 0); + if (!res) + return -EBUSY; + + rc = xa_insert(&cxled->skip_xa, skip_base, res, GFP_KERNEL); + if (rc) { + __release_region(dpa_res, skip_base, skip_len); + return rc; + } + + dev_dbg(dev, "decoder%d.%d: skipped space; %pr\n", + port->id, cxled->cxld.id, res); + return 0; +} + +static int cxl_reserve_dpa_skip(struct cxl_endpoint_decoder *cxled, + resource_size_t base, resource_size_t skipped) +{ + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + struct cxl_port *port = cxled_to_port(cxled); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + resource_size_t skip_base = base - skipped; + struct device *dev = &port->dev; + resource_size_t skip_len = 0; + int rc, index; + + if (resource_size(&cxlds->ram_res) && skip_base <= cxlds->ram_res.end) { + skip_len = cxlds->ram_res.end - skip_base + 1; + rc = cxl_request_skip(cxled, skip_base, skip_len); + if (rc) + return rc; + skip_base += skip_len; + } + + if (skip_base == base) { + dev_dbg(dev, "skip done ram!\n"); + return 0; + } + + if (resource_size(&cxlds->pmem_res) && + skip_base <= cxlds->pmem_res.end) { + skip_len = cxlds->pmem_res.end - skip_base + 1; + rc = cxl_request_skip(cxled, skip_base, skip_len); + if (rc) + return rc; + skip_base += skip_len; + } + + index = dc_mode_to_region_index(cxled->mode); + for (int i = 0; i <= index; i++) { + struct resource *dcr = &cxlds->dc_res[i]; + + if (skip_base < dcr->start) { + skip_len = dcr->start - skip_base; + rc = cxl_request_skip(cxled, skip_base, skip_len); + if (rc) + return rc; + skip_base += skip_len; + } + + if (skip_base == base) { + dev_dbg(dev, "skip done DC region %d!\n", i); + break; + } + + if (resource_size(dcr) && skip_base <= dcr->end) { + if (skip_base > base) { + dev_err(dev, "Skip error DC region %d; skip_base %pa; base %pa\n", + i, &skip_base, &base); + return -ENXIO; + } + + skip_len = dcr->end - skip_base + 1; + rc = cxl_request_skip(cxled, skip_base, skip_len); + if (rc) + return rc; + skip_base += skip_len; + } + } + + return 0; +} + static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, resource_size_t base, resource_size_t len, resource_size_t skipped) @@ -305,13 +417,12 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, } if (skipped) { - res = __request_region(&cxlds->dpa_res, base - skipped, skipped, - dev_name(&cxled->cxld.dev), 0); - if (!res) { - dev_dbg(dev, - "decoder%d.%d: failed to reserve skipped space\n", - port->id, cxled->cxld.id); - return -EBUSY; + int rc = cxl_reserve_dpa_skip(cxled, base, skipped); + + if (rc) { + dev_dbg(dev, "decoder%d.%d: failed to reserve skipped space; %pa - %pa\n", + port->id, cxled->cxld.id, &base, &skipped); + return rc; } } res = __request_region(&cxlds->dpa_res, base, len, @@ -319,14 +430,20 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, if (!res) { dev_dbg(dev, "decoder%d.%d: failed to reserve allocation\n", port->id, cxled->cxld.id); - if (skipped) - __release_region(&cxlds->dpa_res, base - skipped, - skipped); + cxl_skip_release(cxled); return -EBUSY; } cxled->dpa_res = res; cxled->skip = skipped; + for (int mode = CXL_DECODER_DC0; mode <= CXL_DECODER_DC7; mode++) { + int index = dc_mode_to_region_index(mode); + + if (resource_contains(&cxlds->dc_res[index], res)) { + cxled->mode = mode; + goto success; + } + } if (resource_contains(&cxlds->pmem_res, res)) cxled->mode = CXL_DECODER_PMEM; else if (resource_contains(&cxlds->ram_res, res)) @@ -337,6 +454,9 @@ static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, cxled->mode = CXL_DECODER_MIXED; } +success: + dev_dbg(dev, "decoder%d.%d: %pr mode: %d\n", port->id, cxled->cxld.id, + cxled->dpa_res, cxled->mode); port->hdm_end++; get_device(&cxled->cxld.dev); return 0; @@ -457,8 +577,8 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size) { - struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); resource_size_t free_ram_start, free_pmem_start; + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); struct cxl_port *port = cxled_to_port(cxled); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct device *dev = &cxled->cxld.dev; @@ -515,12 +635,54 @@ int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size) else skip_end = start - 1; skip = skip_end - skip_start + 1; + } else if (cxl_decoder_mode_is_dc(cxled->mode)) { + int dc_index = dc_mode_to_region_index(cxled->mode); + + for (p = cxlds->dc_res[dc_index].child, last = NULL; p; p = p->sibling) + last = p; + + if (last) { + /* + * Some capacity in this DC partition is already allocated, + * that allocation already handled the skip. + */ + start = last->end + 1; + skip = 0; + } else { + /* Calculate skip */ + resource_size_t skip_start, skip_end; + + start = cxlds->dc_res[dc_index].start; + + if ((resource_size(&cxlds->pmem_res) == 0) || !cxlds->pmem_res.child) + skip_start = free_ram_start; + else + skip_start = free_pmem_start; + /* + * If any dc region is already mapped, then that allocation + * already handled the RAM and PMEM skip. Check for DC region + * skip. + */ + for (int i = dc_index - 1; i >= 0 ; i--) { + if (cxlds->dc_res[i].child) { + skip_start = cxlds->dc_res[i].child->end + 1; + break; + } + } + + skip_end = start - 1; + skip = skip_end - skip_start + 1; + } + avail = cxlds->dc_res[dc_index].end - start + 1; } else { dev_dbg(dev, "mode not set\n"); rc = -EINVAL; goto out; } + dev_dbg(dev, "DPA Allocation start: %pa len: %#llx Skip: %pa\n", + &start, size, &skip); + if (size > avail) { dev_dbg(dev, "%pa exceeds available %s capacity: %pa\n", &size, cxl_decoder_mode_name(cxled->mode), &avail); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e666ec6a9085a577c92f5e73cefff894922fcb38..85b912c11f04d2c743936eaac1f356975cb3cc71 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -419,6 +419,7 @@ static void cxl_endpoint_decoder_release(struct device *dev) struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); __cxl_decoder_release(&cxled->cxld); + xa_destroy(&cxled->skip_xa); kfree(cxled); } @@ -1899,6 +1900,7 @@ struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port) return ERR_PTR(-ENOMEM); cxled->pos = -1; + xa_init(&cxled->skip_xa); cxld = &cxled->cxld; rc = cxl_decoder_init(port, cxld); if (rc) { diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index f931ebdd36d05a8aa758627746f0fa425a5f14fd..8b7099c38a40d842e4f11137c3e9107031fbdf6a 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -446,6 +446,7 @@ enum cxl_decoder_state { * @cxld: base cxl_decoder_object * @dpa_res: actively claimed DPA span of this decoder * @skip: offset into @dpa_res where @cxld.hpa_range maps + * @skip_xa: array of skipped resources from the previous decoder end * @mode: which memory type / access-mode-partition this decoder targets * @state: autodiscovery state * @pos: interleave position in @cxld.region @@ -454,6 +455,7 @@ struct cxl_endpoint_decoder { struct cxl_decoder cxld; struct resource *dpa_res; resource_size_t skip; + struct xarray skip_xa; enum cxl_decoder_mode mode; enum cxl_decoder_state state; int pos; From patchwork Thu Nov 7 20:58:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867143 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 12A1E21C191; Thu, 7 Nov 2024 20:58:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013138; cv=none; b=vCyITg1XAohelTCCqjhlhi8iU+GGeQ5xW0oLyHELp2i5IVbrz0q2EVGqAOGF6Y6oOYsLqzKqWcjM0TwaEvrledE+4LyP0UZP6wQwVVlpNyCzxVE9jIC2E+UjKyfQlkVjUot+NmU2MncbjqLKfqvqgNSBr1WGa92VYbEC2EBrRXs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013138; c=relaxed/simple; bh=qogwsYpOk+Hm9JKEvIOsX5NUGdyAzbUw8ngMTIyJ/vA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sPXkBE9X/IRj8Xg9fUBK121s1Bqczmx9IOSBD2dlsuTxmSWmcA9sfAb5+1qDOD4R2M6sebMbq7AwBY3SKXEs4jToWueOcxAspbYgdL3zXkwABi5ORNqgTB48Ty7cAVVeAZJxvM9cs686uONlAp/uDBlbG6xM79qv1P5FfHaqzZk= 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=HF3B0ua0; arc=none smtp.client-ip=198.175.65.11 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="HF3B0ua0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013137; x=1762549137; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=qogwsYpOk+Hm9JKEvIOsX5NUGdyAzbUw8ngMTIyJ/vA=; b=HF3B0ua0OU991p559O5rV/5kmOQGj07pvuwyHOiMNtdZfnOoK7vaGMnS C+wK0EGzr5SbdJMX40IvLVN6cD81j0MzFR8eg2tQfKGGGScZ7hGKb1GLs +ItEPEXCzdNnDm4GECvL3LCKiqxH/RpufOexoSbQPgug14PS+QI/mvP3E QeN8ZsYSeeHZDRj/0Atw0VueMPHdBHVwUY6neXlOunQ5EiQBMIh+aln3N kOC32vgFvRuZLbP0PZL3xSag7B2dlRpqyuO9s/znYxQ4tKaep/H6qOZJ3 8h7Vg6c+UaWg1DUD0k8a0dt8q41P8vT3rmPww8ZhZBABapHdiYG9PaK7U A==; X-CSE-ConnectionGUID: ZgmPfA0cQ4uP/EK26YbdEQ== X-CSE-MsgGUID: I8CSURq4QSOkkemWjr4c8Q== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441014" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441014" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:57 -0800 X-CSE-ConnectionGUID: k89L6qIJRVeiBJdywNX25w== X-CSE-MsgGUID: D2J8me70SmK0mqp7aTe8+Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746009" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:56 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:30 -0600 Subject: [PATCH v7 12/27] cxl/cdat: Gather DSMAS data for DCD regions Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-12-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=4616; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=qogwsYpOk+Hm9JKEvIOsX5NUGdyAzbUw8ngMTIyJ/vA=; b=YpaGn9DGfTNL19Qjjn6L089eyepHnZiAydMKkzaUjcQKwJZoPOgKzQ08SnrtJuFdlNdZGjqne 3PV8cotAU5sAoryYeuVCNjNIRRLrUg2stNkcQ0voB3Jy6w33OKGkpjr X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Additional DCD region (partition) information is contained in the DSMAS CDAT tables, including performance, read only, and shareable attributes. Match DCD partitions with DSMAS tables and store the meta data. Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- drivers/cxl/core/cdat.c | 39 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/mbox.c | 2 ++ drivers/cxl/cxlmem.h | 3 +++ 3 files changed, 44 insertions(+) diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c index b5d30c5bf1e20725d13b4397a7ba90662bcd8766..7cd7734a3b0f0b742ee6e63973d12fb3e83ac332 100644 --- a/drivers/cxl/core/cdat.c +++ b/drivers/cxl/core/cdat.c @@ -17,6 +17,8 @@ struct dsmas_entry { struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX]; int entries; int qos_class; + bool shareable; + bool read_only; }; static u32 cdat_normalize(u16 entry, u64 base, u8 type) @@ -74,6 +76,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg, return -ENOMEM; dent->handle = dsmas->dsmad_handle; + dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE; + dent->read_only = dsmas->flags & ACPI_CDAT_DSMAS_READ_ONLY; dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address); dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) + le64_to_cpu((__force __le64)dsmas->dpa_length) - 1; @@ -255,6 +259,39 @@ static void update_perf_entry(struct device *dev, struct dsmas_entry *dent, dent->coord[ACCESS_COORDINATE_CPU].write_latency); } +static void update_dcd_perf(struct cxl_dev_state *cxlds, + struct dsmas_entry *dent) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct device *dev = cxlds->dev; + + for (int i = 0; i < mds->nr_dc_region; i++) { + /* CXL defines a u32 handle while CDAT defines u8, ignore upper bits */ + u8 dc_handle = mds->dc_region[i].dsmad_handle & 0xff; + + if (resource_size(&cxlds->dc_res[i])) { + struct range dc_range = { + .start = cxlds->dc_res[i].start, + .end = cxlds->dc_res[i].end, + }; + + if (range_contains(&dent->dpa_range, &dc_range)) { + if (dent->handle != dc_handle) + dev_warn(dev, "DC Region/DSMAS mis-matched handle/range; region [range 0x%016llx-0x%016llx] (%u); dsmas [range 0x%016llx-0x%016llx] (%u)\n" + " setting DC region attributes regardless\n", + dent->dpa_range.start, dent->dpa_range.end, + dent->handle, + dc_range.start, dc_range.end, + dc_handle); + + mds->dc_region[i].shareable = dent->shareable; + mds->dc_region[i].read_only = dent->read_only; + update_perf_entry(dev, dent, &mds->dc_perf[i]); + } + } + } +} + static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds, struct xarray *dsmas_xa) { @@ -278,6 +315,8 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds, else if (resource_size(&cxlds->pmem_res) && range_contains(&pmem_range, &dent->dpa_range)) update_perf_entry(dev, dent, &mds->pmem_perf); + else if (cxl_dcd_supported(mds)) + update_dcd_perf(cxlds, dent); else dev_dbg(dev, "no partition for dsmas dpa: %#llx\n", dent->dpa_range.start); diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 2c9a9af3dde3a294cde628880066b514b870029f..a4b5cb61b4e6f9b17e3e3e0cce356b0ac9f960d0 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1649,6 +1649,8 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) mds->cxlds.type = CXL_DEVTYPE_CLASSMEM; mds->ram_perf.qos_class = CXL_QOS_CLASS_INVALID; mds->pmem_perf.qos_class = CXL_QOS_CLASS_INVALID; + for (int i = 0; i < CXL_MAX_DC_REGION; i++) + mds->dc_perf[i].qos_class = CXL_QOS_CLASS_INVALID; return mds; } diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 05a0718aea73b3b2a02c608bae198eac7c462523..bbdf52ac1d5cb5df82812c13ff50ca7cacfd0db6 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -466,6 +466,8 @@ struct cxl_dc_region_info { u64 blk_size; u32 dsmad_handle; u8 flags; + bool shareable; + bool read_only; u8 name[CXL_DC_REGION_STRLEN]; }; @@ -533,6 +535,7 @@ struct cxl_memdev_state { u8 nr_dc_region; struct cxl_dc_region_info dc_region[CXL_MAX_DC_REGION]; + struct cxl_dpa_perf dc_perf[CXL_MAX_DC_REGION]; struct cxl_event_state event; struct cxl_poison_state poison; From patchwork Thu Nov 7 20:58:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867144 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 D09DF218593; Thu, 7 Nov 2024 20:58:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013141; cv=none; b=Q0YjqEiFmSKoeUq9rSxrLZm3QPAMdO2x5TgKy51oefeY+VqSBRvxJixCocXXCcwp3ccSflqmW0tvcKt4fx+Cv+d0QynXWw+5XIwH+7Xq0YMTwDTJnh6wip8+qlaTbINrVLbmzFJRYk+NyazUUKgPzhQOI7+SVLT7jNgO4TaLVgg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013141; c=relaxed/simple; bh=4xaMRMyWGYgrPuPjyvJaRxNXkkfAR0XYpHT99FiPWYY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CKst7x9xbCS3wRJAuYmIVqtvZ35YTYeAK5Hy0F5Tx7jxGLotEUiQ7ntJa97DJ/RLYOaMaAJL55UTLkuCjlwYmrg/cnEJmeSY3yzdCmE5mk6CG/xVKP0PV3fK9+6cFYng/MOu2/bRO72awoWZkd/ffTf/MpW2kMW8lwZXqVgNfxk= 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=E6B3g1p/; arc=none smtp.client-ip=198.175.65.11 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="E6B3g1p/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013140; x=1762549140; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=4xaMRMyWGYgrPuPjyvJaRxNXkkfAR0XYpHT99FiPWYY=; b=E6B3g1p/P53G3XJ3KH8xlbga7QhylSTVV8HhymF61YxSBmB8m6dPHYd/ i+ccbPtTZxBvDwX7Yvpsjk0W8tGkYswAZfQeTM20+6hy80eEXmS9a4/tb pJH6sV4j38FAOUdx9qUjKlgMsgB23cdOfEhL/LIibHZbb17i9FhuDmwJD cQSyXHMy25Ws2y9LMWD6jfZNjShFBrqZonHd+LDvbaVphKP5IS9l8Fe0H hJfZ57Dhf9FWXH2dbwEMQ/ipzo23+4aC7Nu3QwJVoYYN2JF/NzufWFS1e DZxP902UL56B2uFZVvUQZoawewfsYyg//RljFlBv3y2gaXyAaoj4kHIBR Q==; X-CSE-ConnectionGUID: AWtYNaNgRLeKywSgG7LWNA== X-CSE-MsgGUID: RnpfVBLtTpOTUOZeZnS/oQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441021" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441021" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:59 -0800 X-CSE-ConnectionGUID: tEz0Ox4DSce7OXNie48pBA== X-CSE-MsgGUID: Vj4jzowTT66IXc5j4wCyPw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746014" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:58:58 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:31 -0600 Subject: [PATCH v7 13/27] cxl/mem: Expose DCD partition capabilities in sysfs Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-13-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=8362; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=v70diWXu9mDxn9Gpd1u2NdGBAzSS3pHisSoxWHpPoyg=; b=NAZMJKOlMmzoz+T1ymwKNaa9Yj15cftaJg1fzOUORfBNEMXdiHwM2ancQC1L1pQgKQlBQGlqF 5rSCv9QP0EgDCIeo++BCdh2SfGOw+37QlZLXmuFKok9ZfxEGWuHDGSw X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh To properly configure CXL regions on Dynamic Capacity Devices (DCD), user space will need to know the details of the DC partitions available. Expose dynamic capacity capabilities through sysfs. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- Documentation/ABI/testing/sysfs-bus-cxl | 45 ++++++++++++ drivers/cxl/core/memdev.c | 124 ++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index 3f5627a1210a16aca7c18d17131a56491048a0c2..ff3ae83477f0876c0ee2d3955d27a11fa9d16d83 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -54,6 +54,51 @@ Description: identically named field in the Identify Memory Device Output Payload in the CXL-2.0 specification. +What: /sys/bus/cxl/devices/memX/dcY/size +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) Dynamic Capacity (DC) region information. Devices only + export dcY if DCD partition Y is supported. + dcY/size is the size of each of those partitions. + +What: /sys/bus/cxl/devices/memX/dcY/read_only +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) Dynamic Capacity (DC) region information. Devices only + export dcY if DCD partition Y is supported. + dcY/read_only indicates true if the region is exported + read_only from the device. + +What: /sys/bus/cxl/devices/memX/dcY/shareable +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) Dynamic Capacity (DC) region information. Devices only + export dcY if DCD partition Y is supported. + dcY/shareable indicates true if the region is exported + shareable from the device. + +What: /sys/bus/cxl/devices/memX/dcY/qos_class +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) Dynamic Capacity (DC) region information. Devices only + export dcY if DCD partition Y is supported. For CXL host + platforms that support "QoS Telemmetry" this attribute conveys + a comma delimited list of platform specific cookies that + identifies a QoS performance class for the persistent partition + of the CXL mem device. These class-ids can be compared against + a similar "qos_class" published for a root decoder. While it is + not required that the endpoints map their local memory-class to + a matching platform class, mismatches are not recommended as + there are platform specific performance related side-effects + that may result. First class-id is displayed. What: /sys/bus/cxl/devices/memX/pmem/qos_class Date: May, 2023 diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 84fefb76dafabc22e6e1a12397381b3f18eea7c5..857a9dd88b20291116d20b9c0bbe9e7961f4491f 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -2,6 +2,7 @@ /* Copyright(c) 2020 Intel Corporation. */ #include +#include #include #include #include @@ -449,6 +450,121 @@ static struct attribute *cxl_memdev_security_attributes[] = { NULL, }; +static ssize_t show_size_dcN(struct cxl_memdev *cxlmd, char *buf, int pos) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + return sysfs_emit(buf, "%#llx\n", mds->dc_region[pos].decode_len); +} + +static ssize_t show_read_only_dcN(struct cxl_memdev *cxlmd, char *buf, int pos) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + return sysfs_emit(buf, "%s\n", + str_true_false(mds->dc_region[pos].read_only)); +} + +static ssize_t show_shareable_dcN(struct cxl_memdev *cxlmd, char *buf, int pos) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + return sysfs_emit(buf, "%s\n", + str_true_false(mds->dc_region[pos].shareable)); +} + +static ssize_t show_qos_class_dcN(struct cxl_memdev *cxlmd, char *buf, int pos) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + + return sysfs_emit(buf, "%d\n", mds->dc_perf[pos].qos_class); +} + +#define CXL_MEMDEV_DC_ATTR_GROUP(n) \ +static ssize_t dc##n##_size_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_size_dcN(to_cxl_memdev(dev), buf, (n)); \ +} \ +struct device_attribute dc##n##_size = { \ + .attr = { .name = "size", .mode = 0444 }, \ + .show = dc##n##_size_show, \ +}; \ +static ssize_t dc##n##_read_only_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_read_only_dcN(to_cxl_memdev(dev), buf, (n)); \ +} \ +struct device_attribute dc##n##_read_only = { \ + .attr = { .name = "read_only", .mode = 0444 }, \ + .show = dc##n##_read_only_show, \ +}; \ +static ssize_t dc##n##_shareable_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_shareable_dcN(to_cxl_memdev(dev), buf, (n)); \ +} \ +struct device_attribute dc##n##_shareable = { \ + .attr = { .name = "shareable", .mode = 0444 }, \ + .show = dc##n##_shareable_show, \ +}; \ +static ssize_t dc##n##_qos_class_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return show_qos_class_dcN(to_cxl_memdev(dev), buf, (n)); \ +} \ +struct device_attribute dc##n##_qos_class = { \ + .attr = { .name = "qos_class", .mode = 0444 }, \ + .show = dc##n##_qos_class_show, \ +}; \ +static struct attribute *cxl_memdev_dc##n##_attributes[] = { \ + &dc##n##_size.attr, \ + &dc##n##_read_only.attr, \ + &dc##n##_shareable.attr, \ + &dc##n##_qos_class.attr, \ + NULL \ +}; \ +static umode_t cxl_memdev_dc##n##_attr_visible(struct kobject *kobj, \ + struct attribute *a, \ + int pos) \ +{ \ + struct device *dev = kobj_to_dev(kobj); \ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); \ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); \ + \ + /* Not a memory device */ \ + if (!mds) \ + return 0; \ + return a->mode; \ +} \ +static umode_t cxl_memdev_dc##n##_group_visible(struct kobject *kobj) \ +{ \ + struct device *dev = kobj_to_dev(kobj); \ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); \ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); \ + \ + /* Not a memory device or partition not supported */ \ + return mds && n < mds->nr_dc_region; \ +} \ +DEFINE_SYSFS_GROUP_VISIBLE(cxl_memdev_dc##n); \ +static struct attribute_group cxl_memdev_dc##n##_group = { \ + .name = "dc"#n, \ + .attrs = cxl_memdev_dc##n##_attributes, \ + .is_visible = SYSFS_GROUP_VISIBLE(cxl_memdev_dc##n), \ +} +CXL_MEMDEV_DC_ATTR_GROUP(0); +CXL_MEMDEV_DC_ATTR_GROUP(1); +CXL_MEMDEV_DC_ATTR_GROUP(2); +CXL_MEMDEV_DC_ATTR_GROUP(3); +CXL_MEMDEV_DC_ATTR_GROUP(4); +CXL_MEMDEV_DC_ATTR_GROUP(5); +CXL_MEMDEV_DC_ATTR_GROUP(6); +CXL_MEMDEV_DC_ATTR_GROUP(7); + static umode_t cxl_memdev_visible(struct kobject *kobj, struct attribute *a, int n) { @@ -525,6 +641,14 @@ static struct attribute_group cxl_memdev_security_attribute_group = { }; static const struct attribute_group *cxl_memdev_attribute_groups[] = { + &cxl_memdev_dc0_group, + &cxl_memdev_dc1_group, + &cxl_memdev_dc2_group, + &cxl_memdev_dc3_group, + &cxl_memdev_dc4_group, + &cxl_memdev_dc5_group, + &cxl_memdev_dc6_group, + &cxl_memdev_dc7_group, &cxl_memdev_attribute_group, &cxl_memdev_ram_attribute_group, &cxl_memdev_pmem_attribute_group, From patchwork Thu Nov 7 20:58:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867145 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 D85EC21FD8E; Thu, 7 Nov 2024 20:59:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013143; cv=none; b=qQzgXs4B+msXuXJyF6ld31hMYDSIOxij5yq2d94GJrF03F6uhEiP8RPxt3Xeh1UpOFMV80U/BncTUIQHZYgmHvVy0mHicOLG93Aj5L2K7OGD2TMYupzNWfnCcUO70Ip2Krit5QY7suvXQynAnV8hRfTAZB34b0cjpGPUzrt3fgU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013143; c=relaxed/simple; bh=Ik5VP6IO2+Sl0l25uKW5XK4yMsZRV1pydB1PU8xjNlw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uo6GDKu9+CwAjMzvngPVlsSc733zmjPEYjmVkFXrf4291DxfRV3jtTGFUL35FthMoPQk3Ysw40VLobOfcHRDfypuWmLMh9hCX9hxsebXbavESEcLWidB2ce0X5ourbnrPJdb6hroRAK84/CMxiiWY7VXyQTXK8oG38cK2F4ErTM= 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=W6IdT50R; arc=none smtp.client-ip=198.175.65.11 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="W6IdT50R" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013142; x=1762549142; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=Ik5VP6IO2+Sl0l25uKW5XK4yMsZRV1pydB1PU8xjNlw=; b=W6IdT50Ra9pREod3GmWgi7avVByNJ99wNhUG+iBY2rwCJWtlJm/pEblx UPTJ7ulzJT1LcWdfSBV3TarC5L5aFooVJNCyC1ItRU77zyB/34bKwduyu AXU302tZyVrnIvKKFbT/FMcs36BBPrHYC2LGJoc9iLW15DYPIVWWweDt+ 7zTSU034WaNhvi1J0w43kopJ5lh6uXkKWnD2hs3CX38QYwl4/Ktt9Bep+ PYjyLwyUxqDbySkHyHxzLh75OE+Xty8t5XY22iTwIzgv2PaZtLhHm9Is4 mGSPfO5AtK8DJo0kyJtp0OeTwjU9IpCvZkC8wZYvlNntKm0ZVWzJjNkG+ A==; X-CSE-ConnectionGUID: FSLu4N02Rry9xovZuFywOg== X-CSE-MsgGUID: lXV2iTNuRSa6YgZlHZcmqQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441029" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441029" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:01 -0800 X-CSE-ConnectionGUID: lz4+fpn1ScionhH4NHQWNw== X-CSE-MsgGUID: 2CJK7N7CRbGSZC1UNxGxAQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746019" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:00 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:32 -0600 Subject: [PATCH v7 14/27] cxl/port: Add endpoint decoder DC mode support to sysfs Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-14-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=6278; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=94u2ZU2KhMC3r6DSXpzSgMHBRS/GwJgXxPJvIMLN8II=; b=2aZqFInzys18Fq7saOEVE0AWy8pltLOhHq0t5Hahs2aV2DX/WJ48z62XRZeutKqiKv4vKH3Yp B2T7uZXfd5/B2j7ejSx+GdM2EiuI5hrY4OXqnPiLTAbzGAd6K152gGo X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Endpoint decoder mode is used to represent the partition the decoder points to such as ram or pmem. Expand the mode to allow a decoder to point to a specific DC partition (Region). Signed-off-by: Navneet Singh Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- Changes: [Carpenter/smatch: fix cxl_decoder_mode_names array] --- Documentation/ABI/testing/sysfs-bus-cxl | 25 ++++++++++++------------ drivers/cxl/core/hdm.c | 16 ++++++++++++++++ drivers/cxl/core/port.c | 16 +++++++++++----- drivers/cxl/cxl.h | 34 +++++++++++++++++---------------- 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index ff3ae83477f0876c0ee2d3955d27a11fa9d16d83..8d990d702f63363879150cf523c0be6229f315e0 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -361,23 +361,24 @@ Description: What: /sys/bus/cxl/devices/decoderX.Y/mode -Date: May, 2022 -KernelVersion: v6.0 +Date: May, 2022, October 2024 +KernelVersion: v6.0, v6.13 (dcY) Contact: linux-cxl@vger.kernel.org Description: (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it - translates from a host physical address range, to a device local - address range. Device-local address ranges are further split - into a 'ram' (volatile memory) range and 'pmem' (persistent - memory) range. The 'mode' attribute emits one of 'ram', 'pmem', - 'mixed', or 'none'. The 'mixed' indication is for error cases - when a decoder straddles the volatile/persistent partition - boundary, and 'none' indicates the decoder is not actively - decoding, or no DPA allocation policy has been set. + translates from a host physical address range, to a device + local address range. Device-local address ranges are further + split into a 'ram' (volatile memory) range, 'pmem' (persistent + memory) range, and Dynamic Capacity (DC) ranges. The 'mode' + attribute emits one of 'ram', 'pmem', 'dcY', 'mixed', or + 'none'. The 'mixed' indication is for error cases when a + decoder straddles partition boundaries, and 'none' indicates + the decoder is not actively decoding, or no DPA allocation + policy has been set. 'mode' can be written, when the decoder is in the 'disabled' - state, with either 'ram' or 'pmem' to set the boundaries for the - next allocation. + state, with 'ram', 'pmem', or 'dcY' to set the boundaries for + the next allocation. What: /sys/bus/cxl/devices/decoderX.Y/dpa_resource diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 998aed17d7e47fc18a05fb2e8cca25de0e92a6d4..40799a0ca1d7af89b9af53cc098381e83b8c7e82 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -548,6 +548,7 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, switch (mode) { case CXL_DECODER_RAM: case CXL_DECODER_PMEM: + case CXL_DECODER_DC0 ... CXL_DECODER_DC7: break; default: dev_dbg(dev, "unsupported mode: %d\n", mode); @@ -571,6 +572,21 @@ int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, return -ENXIO; } + if (mode >= CXL_DECODER_DC0 && mode <= CXL_DECODER_DC7) { + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + int index; + + index = dc_mode_to_region_index(mode); + if (!resource_size(&cxlds->dc_res[index])) { + dev_dbg(dev, "no available dynamic capacity\n"); + return -ENXIO; + } + if (mds->dc_region[index].shareable) { + dev_err(dev, "DC region %d is shareable\n", index); + return -EINVAL; + } + } + cxled->mode = mode; return 0; } diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 85b912c11f04d2c743936eaac1f356975cb3cc71..2f42c8717a65586c769f0fd2016e8addc2552f9d 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -205,11 +205,17 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr, enum cxl_decoder_mode mode; ssize_t rc; - if (sysfs_streq(buf, "pmem")) - mode = CXL_DECODER_PMEM; - else if (sysfs_streq(buf, "ram")) - mode = CXL_DECODER_RAM; - else + for (mode = 0; mode < CXL_DECODER_MODE_MAX; mode++) + if (sysfs_streq(buf, cxl_decoder_mode_names[mode])) + break; + + if (mode == CXL_DECODER_NONE || + mode == CXL_DECODER_DEAD || + mode == CXL_DECODER_MODE_MAX) + return -EINVAL; + + /* Not yet supported */ + if (mode >= CXL_DECODER_MIXED) return -EINVAL; rc = cxl_dpa_set_mode(cxled, mode); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 8b7099c38a40d842e4f11137c3e9107031fbdf6a..46cc5ba502b2c46c68fd81c48b06f76f33282878 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -380,27 +380,29 @@ enum cxl_decoder_mode { CXL_DECODER_DC7, CXL_DECODER_MIXED, CXL_DECODER_DEAD, + CXL_DECODER_MODE_MAX, +}; + +static const char * const cxl_decoder_mode_names[] = { + [CXL_DECODER_NONE] = "none", + [CXL_DECODER_RAM] = "ram", + [CXL_DECODER_PMEM] = "pmem", + [CXL_DECODER_DC0] = "dc0", + [CXL_DECODER_DC1] = "dc1", + [CXL_DECODER_DC2] = "dc2", + [CXL_DECODER_DC3] = "dc3", + [CXL_DECODER_DC4] = "dc4", + [CXL_DECODER_DC5] = "dc5", + [CXL_DECODER_DC6] = "dc6", + [CXL_DECODER_DC7] = "dc7", + [CXL_DECODER_MIXED] = "mixed", + [CXL_DECODER_DEAD] = "dead", }; static inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode) { - static const char * const names[] = { - [CXL_DECODER_NONE] = "none", - [CXL_DECODER_RAM] = "ram", - [CXL_DECODER_PMEM] = "pmem", - [CXL_DECODER_DC0] = "dc0", - [CXL_DECODER_DC1] = "dc1", - [CXL_DECODER_DC2] = "dc2", - [CXL_DECODER_DC3] = "dc3", - [CXL_DECODER_DC4] = "dc4", - [CXL_DECODER_DC5] = "dc5", - [CXL_DECODER_DC6] = "dc6", - [CXL_DECODER_DC7] = "dc7", - [CXL_DECODER_MIXED] = "mixed", - }; - if (mode >= CXL_DECODER_NONE && mode <= CXL_DECODER_MIXED) - return names[mode]; + return cxl_decoder_mode_names[mode]; return "mixed"; } From patchwork Thu Nov 7 20:58:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867146 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 3A8AC21F4DE; Thu, 7 Nov 2024 20:59:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013146; cv=none; b=qr1XKBVKR2Dohsgzj3UicU0G14BI3xQ/hcEDPk3mjnPw3LUSZxWxI2Y/fNEWmwSNn4Cc/CQ2yRW8cHMJFZNObv9gUbOZTMP0Y6uhqqkR8IUldoOf1YIYKK4rHwj4hwwuYBRc7h16c9rwXgJqdfv4ltFZNf02+aDF7yfitD1FNIk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013146; c=relaxed/simple; bh=JRh0V38YDcT6tPDtCH0/XEXvjvL2eQo9unAh5i5Tvmg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QsYozpHbmlyf/P0sMMDitwiL1mDsTcD6wo7Xepk2XDGGbhT3sBKvG4EnZLw3DZ2KoOfE/COi3qhYczEEnu4NeLBB21qDrFLKx2phR355Pidvqk8zt9NuHRWl2aqkxCteE5VBEYDvjpnyagly/1UHBl8Aq4EmIZWpotqebbwSWkM= 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=UHpr9WOZ; arc=none smtp.client-ip=198.175.65.11 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="UHpr9WOZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013144; x=1762549144; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=JRh0V38YDcT6tPDtCH0/XEXvjvL2eQo9unAh5i5Tvmg=; b=UHpr9WOZNI5QCYv1SLCwdO5/FlToRFg9TNAj+83ohWxVsgnQ1SXzg9U1 DziHMr2GjBP5f1Z01yigkHn0KUeyf0xHJ4rrSdFMjOXlC0p6ZIB3AQlTj kep5vdd/WG21je2PaupE/S0LzpoZSPj5V9AWkZQKk6cy9QnXlDcBbmHZC P9pu8o1kk9/X9sxZtbkgL1Ke+FonBInhFDOXYtyk9mvK8HG5GlFQI42iX RQtfFSXc7/yHVNtC22y0GI87GQGB0q8wTm7zmayO9HtFkXyA77ES6zB/H 3vDoBZPmZwmxQ3/7zqiHwdkg7aTbFeId9Yhxgoe/XIBJIkFoRenXSV7/Q Q==; X-CSE-ConnectionGUID: yyef2TV5StSUI1HKVBXr4g== X-CSE-MsgGUID: j9D0oPVgQTGv0ISZdV2r0A== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441038" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441038" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:04 -0800 X-CSE-ConnectionGUID: QDSONlnMTGa7q+6Q8UStZg== X-CSE-MsgGUID: hTR+LSoaSny1DN6i+JSXag== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746022" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:03 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:33 -0600 Subject: [PATCH v7 15/27] cxl/region: Add sparse DAX region support Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-15-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=11790; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=+CDIvMYBKRG5f3zYK1SZ76xdWI5Q/cyLSdTOm/V8Gdw=; b=Wj3D8bDXyLCaKzTiFTb9fkC5hZm1FuQyvKTc7bBe5cYCO8p3ACfCJcTj3OXkXj1K/pxdeLdWe l4dmcGgzc/TDNQt8mpaiGtMe+jPSdt7XTKMe7v2KfgdJWhufTgHEBys X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Dynamic Capacity CXL regions must allow memory to be added or removed dynamically. In addition to the quantity of memory available the location of the memory within a DC partition is dynamic based on the extents offered by a device. CXL DAX regions must accommodate the sparseness of this memory in the management of DAX regions and devices. Introduce the concept of a sparse DAX region. Add a create_dc_region() sysfs entry to create such regions. Special case DC capable regions to create a 0 sized seed DAX device to maintain compatibility which requires a default DAX device to hold a region reference. Indicate 0 byte available capacity until such time that capacity is added. Sparse regions complicate the range mapping of dax devices. There is no known use case for range mapping on sparse regions. Avoid the complication by preventing range mapping of dax devices on sparse regions. Interleaving is deferred for now. Add checks. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- Documentation/ABI/testing/sysfs-bus-cxl | 22 ++++++++-------- drivers/cxl/core/core.h | 12 +++++++++ drivers/cxl/core/port.c | 1 + drivers/cxl/core/region.c | 46 +++++++++++++++++++++++++++++++-- drivers/dax/bus.c | 10 +++++++ drivers/dax/bus.h | 1 + drivers/dax/cxl.c | 16 ++++++++++-- 7 files changed, 93 insertions(+), 15 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index 8d990d702f63363879150cf523c0be6229f315e0..aeff248ea368cf49c9977fcaf43ab4def978e896 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -439,20 +439,20 @@ Description: interleave_granularity). -What: /sys/bus/cxl/devices/decoderX.Y/create_{pmem,ram}_region -Date: May, 2022, January, 2023 -KernelVersion: v6.0 (pmem), v6.3 (ram) +What: /sys/bus/cxl/devices/decoderX.Y/create_{pmem,ram,dc}_region +Date: May, 2022, January, 2023, August 2024 +KernelVersion: v6.0 (pmem), v6.3 (ram), v6.13 (dc) Contact: linux-cxl@vger.kernel.org Description: (RW) Write a string in the form 'regionZ' to start the process - of defining a new persistent, or volatile memory region - (interleave-set) within the decode range bounded by root decoder - 'decoderX.Y'. The value written must match the current value - returned from reading this attribute. An atomic compare exchange - operation is done on write to assign the requested id to a - region and allocate the region-id for the next creation attempt. - EBUSY is returned if the region name written does not match the - current cached value. + of defining a new persistent, volatile, or Dynamic Capacity + (DC) memory region (interleave-set) within the decode range + bounded by root decoder 'decoderX.Y'. The value written must + match the current value returned from reading this attribute. + An atomic compare exchange operation is done on write to assign + the requested id to a region and allocate the region-id for the + next creation attempt. EBUSY is returned if the region name + written does not match the current cached value. What: /sys/bus/cxl/devices/decoderX.Y/delete_region diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 0c62b4069ba00a5380d456a516eb7968dc51062b..5d6fe7ab0a78cddb01c7e0d63ed55c36879c4cef 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -4,15 +4,27 @@ #ifndef __CXL_CORE_H__ #define __CXL_CORE_H__ +#include + extern const struct device_type cxl_nvdimm_bridge_type; extern const struct device_type cxl_nvdimm_type; extern const struct device_type cxl_pmu_type; extern struct attribute_group cxl_base_attribute_group; +static inline struct cxl_memdev_state * +cxled_to_mds(struct cxl_endpoint_decoder *cxled) +{ + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + + return container_of(cxlds, struct cxl_memdev_state, cxlds); +} + #ifdef CONFIG_CXL_REGION extern struct device_attribute dev_attr_create_pmem_region; extern struct device_attribute dev_attr_create_ram_region; +extern struct device_attribute dev_attr_create_dc_region; extern struct device_attribute dev_attr_delete_region; extern struct device_attribute dev_attr_region; extern const struct device_type cxl_pmem_region_type; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 2f42c8717a65586c769f0fd2016e8addc2552f9d..0eeb42f14bcab76965dbd0813b29c918007c3021 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -326,6 +326,7 @@ static struct attribute *cxl_decoder_root_attrs[] = { &dev_attr_qos_class.attr, SET_CXL_REGION_ATTR(create_pmem_region) SET_CXL_REGION_ATTR(create_ram_region) + SET_CXL_REGION_ATTR(create_dc_region) SET_CXL_REGION_ATTR(delete_region) NULL, }; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 2ca6148d108cc020bebcb34b09028fa59bb62f02..34a6f447e75b18e6a1c8c27250a3e425bd0cc515 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -496,6 +496,11 @@ static ssize_t interleave_ways_store(struct device *dev, if (rc) return rc; + if (cxlr->mode == CXL_REGION_DC && val != 1) { + dev_err(dev, "Interleaving and DCD not supported\n"); + return -EINVAL; + } + rc = ways_to_eiw(val, &iw); if (rc) return rc; @@ -2176,6 +2181,7 @@ static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos, if (sysfs_streq(buf, "\n")) rc = detach_target(cxlr, pos); else { + struct cxl_endpoint_decoder *cxled; struct device *dev; dev = bus_find_device_by_name(&cxl_bus_type, NULL, buf); @@ -2187,8 +2193,13 @@ static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos, goto out; } - rc = attach_target(cxlr, to_cxl_endpoint_decoder(dev), pos, - TASK_INTERRUPTIBLE); + cxled = to_cxl_endpoint_decoder(dev); + if (cxlr->mode == CXL_REGION_DC && + !cxl_dcd_supported(cxled_to_mds(cxled))) { + dev_dbg(dev, "DCD unsupported\n"); + return -EINVAL; + } + rc = attach_target(cxlr, cxled, pos, TASK_INTERRUPTIBLE); out: put_device(dev); } @@ -2533,6 +2544,7 @@ static struct cxl_region *__create_region(struct cxl_root_decoder *cxlrd, switch (mode) { case CXL_REGION_RAM: case CXL_REGION_PMEM: + case CXL_REGION_DC: break; default: dev_err(&cxlrd->cxlsd.cxld.dev, "unsupported mode %s\n", @@ -2586,6 +2598,20 @@ static ssize_t create_ram_region_store(struct device *dev, } DEVICE_ATTR_RW(create_ram_region); +static ssize_t create_dc_region_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return __create_region_show(to_cxl_root_decoder(dev), buf); +} + +static ssize_t create_dc_region_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return create_region_store(dev, buf, len, CXL_REGION_DC); +} +DEVICE_ATTR_RW(create_dc_region); + static ssize_t region_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -3168,6 +3194,11 @@ static int devm_cxl_add_dax_region(struct cxl_region *cxlr) struct device *dev; int rc; + if (cxlr->mode == CXL_REGION_DC && cxlr->params.interleave_ways != 1) { + dev_err(&cxlr->dev, "Interleaving DC not supported\n"); + return -EINVAL; + } + cxlr_dax = cxl_dax_region_alloc(cxlr); if (IS_ERR(cxlr_dax)) return PTR_ERR(cxlr_dax); @@ -3260,6 +3291,16 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, return ERR_PTR(-EINVAL); mode = cxl_decoder_to_region_mode(cxled->mode); + if (mode == CXL_REGION_DC) { + if (!cxl_dcd_supported(cxled_to_mds(cxled))) { + dev_err(&cxled->cxld.dev, "DCD unsupported\n"); + return ERR_PTR(-EINVAL); + } + if (cxled->cxld.interleave_ways != 1) { + dev_err(&cxled->cxld.dev, "Interleaving and DCD not supported\n"); + return ERR_PTR(-EINVAL); + } + } do { cxlr = __create_region(cxlrd, mode, atomic_read(&cxlrd->region_id)); @@ -3467,6 +3508,7 @@ static int cxl_region_probe(struct device *dev) case CXL_REGION_PMEM: return devm_cxl_add_pmem_region(cxlr); case CXL_REGION_RAM: + case CXL_REGION_DC: /* * The region can not be manged by CXL if any portion of * it is already online as 'System RAM' diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index fde29e0ad68b158c5c88262d434ee7b55a5ce407..d8cb5195a227c0f6194cb210510e006327e1b35b 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -178,6 +178,11 @@ static bool is_static(struct dax_region *dax_region) return (dax_region->res.flags & IORESOURCE_DAX_STATIC) != 0; } +static bool is_sparse(struct dax_region *dax_region) +{ + return (dax_region->res.flags & IORESOURCE_DAX_SPARSE_CAP) != 0; +} + bool static_dev_dax(struct dev_dax *dev_dax) { return is_static(dev_dax->region); @@ -301,6 +306,9 @@ static unsigned long long dax_region_avail_size(struct dax_region *dax_region) lockdep_assert_held(&dax_region_rwsem); + if (is_sparse(dax_region)) + return 0; + for_each_dax_region_resource(dax_region, res) size -= resource_size(res); return size; @@ -1373,6 +1381,8 @@ static umode_t dev_dax_visible(struct kobject *kobj, struct attribute *a, int n) return 0; if (a == &dev_attr_mapping.attr && is_static(dax_region)) return 0; + if (a == &dev_attr_mapping.attr && is_sparse(dax_region)) + return 0; if ((a == &dev_attr_align.attr || a == &dev_attr_size.attr) && is_static(dax_region)) return 0444; diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index cbbf64443098c08d944878a190a0da69eccbfbf4..783bfeef42cc6c4d74f24e0a69dac5598eaf1664 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -13,6 +13,7 @@ struct dax_region; /* dax bus specific ioresource flags */ #define IORESOURCE_DAX_STATIC BIT(0) #define IORESOURCE_DAX_KMEM BIT(1) +#define IORESOURCE_DAX_SPARSE_CAP BIT(2) struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct range *range, int target_node, unsigned int align, diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c index 9b29e732b39a691fbd8ac0391b477b1584b59568..367e86b1c22a2a0af7070677a7b7fc54bc2b0214 100644 --- a/drivers/dax/cxl.c +++ b/drivers/dax/cxl.c @@ -13,19 +13,31 @@ static int cxl_dax_region_probe(struct device *dev) struct cxl_region *cxlr = cxlr_dax->cxlr; struct dax_region *dax_region; struct dev_dax_data data; + resource_size_t dev_size; + unsigned long flags; if (nid == NUMA_NO_NODE) nid = memory_add_physaddr_to_nid(cxlr_dax->hpa_range.start); + flags = IORESOURCE_DAX_KMEM; + if (cxlr->mode == CXL_REGION_DC) + flags |= IORESOURCE_DAX_SPARSE_CAP; + dax_region = alloc_dax_region(dev, cxlr->id, &cxlr_dax->hpa_range, nid, - PMD_SIZE, IORESOURCE_DAX_KMEM); + PMD_SIZE, flags); if (!dax_region) return -ENOMEM; + if (cxlr->mode == CXL_REGION_DC) + /* Add empty seed dax device */ + dev_size = 0; + else + dev_size = range_len(&cxlr_dax->hpa_range); + data = (struct dev_dax_data) { .dax_region = dax_region, .id = -1, - .size = range_len(&cxlr_dax->hpa_range), + .size = dev_size, .memmap_on_memory = true, }; From patchwork Thu Nov 7 20:58:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867147 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 3E271223A47; Thu, 7 Nov 2024 20:59:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013147; cv=none; b=el0xnpGM1zSz4qa+RWqc3qQB0ntSnoTt6KGY3A2NsGSHWk4EpFYnzk0d+VVJAKN1UpZTbyy1fxbzNqt5+kbGdf06rokgdzWHg1oghtaogCMTM/NuH2wBoARLoBkB+BSzpor1AD2qwyOC15G4pbM6G4Tu/eNcIAccWXjZKBKEtKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013147; c=relaxed/simple; bh=SiMgcrGnVQyiKC7DqMtxFALjaH10RqY0abQa+E/1rcw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oKF+L+VmxAl9tUWBzxs/5WdErp5i3WpW9MXnTVQ+QF02bYy1ORYRSNich6mLHlKnpFEQcUxD6tFiKXxBmcQNIpb/XCZQy9LXSKb/cqkEtl3gviDLNLpLrVLWQHoR9s6NioerJ9j1XVXpuTg9nyte5AJdYRHd9Q/zm3FKIJrwrGQ= 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=i9Wu+1dv; arc=none smtp.client-ip=198.175.65.11 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="i9Wu+1dv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013146; x=1762549146; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=SiMgcrGnVQyiKC7DqMtxFALjaH10RqY0abQa+E/1rcw=; b=i9Wu+1dvf6JvM3NnzR+OjZqJzmCb4v3h3qoxw+7KgxMtq4XKjjC4gLL5 aVgpumnLdlfndMuU6EQgo9PSJsEj9e32OaBtYhAvsqDcxgUoA8iaLQpkh ng6IfSIa6aChn//fbjuP2Ie9fN7UkqtFJsb1mpV0VdAjAKO4wURd8nGoe wL1I7y+GHZxVBI0usdLbAPNnSq298ry8RtpuWSy1iHwKH/SpP46EGEe59 Fq36MpD70gWyUz0WOuIjs7HJVIpCmAHnzD98FEPkKFfagagBwwsSajUEs O8Go6sgWjMSv9s1NsyMBljIKVPcMANT7yoC6Er0Y3KWDtq3eDbQOBN9YA Q==; X-CSE-ConnectionGUID: dx+M3vdBTCqyqyM1P9i7GQ== X-CSE-MsgGUID: SbNjkWEWSDifO/0eDRZPnA== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441046" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441046" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:06 -0800 X-CSE-ConnectionGUID: fX/4Md7YSZOMvpLwF8KC6Q== X-CSE-MsgGUID: Gd+VReAbSjWqwBXnPd/s4A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746027" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:05 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:34 -0600 Subject: [PATCH v7 16/27] cxl/events: Split event msgnum configuration from irq setup Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-16-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=2685; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=SiMgcrGnVQyiKC7DqMtxFALjaH10RqY0abQa+E/1rcw=; b=gLguDKYrKbSjdQLupwC4Tsed76OxA1kxFpSILmqbqIxz0bGggLgY36x1KfZAgTmnGnBkXX2F6 DhAd1QIhN2FBRvLQ/OJcuV9I9VRfZyQTfVGeFQpE6UQgPL2Zy2mmL+n X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Dynamic Capacity Devices (DCD) require event interrupts to process memory addition or removal. BIOS may have control over non-DCD event processing. DCD interrupt configuration needs to be separate from memory event interrupt configuration. Split cxl_event_config_msgnums() from irq setup in preparation for separate DCD interrupts configuration. Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Li Ming Signed-off-by: Ira Weiny --- drivers/cxl/pci.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index c8454b3ecea5c053bf9723c275652398c0b2a195..8559b0eac011cadd49e67953b7560f49eedff94a 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -702,35 +702,31 @@ static int cxl_event_config_msgnums(struct cxl_memdev_state *mds, return cxl_event_get_int_policy(mds, policy); } -static int cxl_event_irqsetup(struct cxl_memdev_state *mds) +static int cxl_event_irqsetup(struct cxl_memdev_state *mds, + struct cxl_event_interrupt_policy *policy) { struct cxl_dev_state *cxlds = &mds->cxlds; - struct cxl_event_interrupt_policy policy; int rc; - rc = cxl_event_config_msgnums(mds, &policy); - if (rc) - return rc; - - rc = cxl_event_req_irq(cxlds, policy.info_settings); + rc = cxl_event_req_irq(cxlds, policy->info_settings); if (rc) { dev_err(cxlds->dev, "Failed to get interrupt for event Info log\n"); return rc; } - rc = cxl_event_req_irq(cxlds, policy.warn_settings); + rc = cxl_event_req_irq(cxlds, policy->warn_settings); if (rc) { dev_err(cxlds->dev, "Failed to get interrupt for event Warn log\n"); return rc; } - rc = cxl_event_req_irq(cxlds, policy.failure_settings); + rc = cxl_event_req_irq(cxlds, policy->failure_settings); if (rc) { dev_err(cxlds->dev, "Failed to get interrupt for event Failure log\n"); return rc; } - rc = cxl_event_req_irq(cxlds, policy.fatal_settings); + rc = cxl_event_req_irq(cxlds, policy->fatal_settings); if (rc) { dev_err(cxlds->dev, "Failed to get interrupt for event Fatal log\n"); return rc; @@ -777,11 +773,15 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, return -EBUSY; } + rc = cxl_event_config_msgnums(mds, &policy); + if (rc) + return rc; + rc = cxl_mem_alloc_event_buf(mds); if (rc) return rc; - rc = cxl_event_irqsetup(mds); + rc = cxl_event_irqsetup(mds, &policy); if (rc) return rc; From patchwork Thu Nov 7 20:58:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867148 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 AE77B223A68; Thu, 7 Nov 2024 20:59:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013150; cv=none; b=tn5Myr76GUvWALfaroC0RycHt5VhKw/qZkWRo19UEm91ILB9NCx/28X3gjIEgh3RwHNcNgonBUJY2lUI+nk6aA6+6Z0NCGggGLxxTS+JSp780+8RMunNqu6Ba3Ps1KsoXECHBMo0HmhUqy29q8mqRZWFAez6JGCXqfeqeWFVnCU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013150; c=relaxed/simple; bh=NLrrvpMgAcSkVfM1wvLzl5lPfI71ou2Lqgos0sbSipI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CYOVRMk+aevB9g22WkHnUv5dEOqcGHzGrewtsWXdIO8i0e4RTcD/ry9B6xD5Zxv/h66a/84IqFSY/JISiqGEudOve5zQ1bG4/3O0XXaROKwlUjxRdQysluuJqU0mO0gKjKoqYsRw6fiY/g1/a4PjUbSayg9nSzvZ+et0GCIHFiM= 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=b0xaHZ21; arc=none smtp.client-ip=198.175.65.11 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="b0xaHZ21" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013149; x=1762549149; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=NLrrvpMgAcSkVfM1wvLzl5lPfI71ou2Lqgos0sbSipI=; b=b0xaHZ2177gDC3jP10S1RZdMkYa6sIJx0eF4W6pLSHdY/IE8XtjQbYxx px+alDsIQLRAtW4CxPN7ArgVeYC4AggPq24/BmF2lG839fdYFhxc1kuiq +j7/1FJ9ZRJ4x9BelFC8iE1GFJw44nXjK4PVeSYVAuwunkjeol106TGrg qK8KZb6hItCkv+6ZaoDbi8CoUGSgUEBnKRL0xyXFnChnmYV5313EOJThZ r/4ZAuauqIe3F70UOu543iau2eXMHfzv6thZz9fM8b3zHtmIgUzjNcHRp Cjsf32HjYVAPRCR4uWuwDwLkb+U8Hz8c+gbhqBj5ifhH602yLPAo4Jp8c Q==; X-CSE-ConnectionGUID: ZkWg6nlAS++DityBq8HUdA== X-CSE-MsgGUID: SfOkCrWYQJyG59OAAmCoHA== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441054" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441054" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:08 -0800 X-CSE-ConnectionGUID: ncu/vzbcT3GtR6VY9EHnBg== X-CSE-MsgGUID: KeUFTaatTeyJTbjDsJpwDw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746031" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:07 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:35 -0600 Subject: [PATCH v7 17/27] cxl/pci: Factor out interrupt policy check Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-17-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=2296; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=NLrrvpMgAcSkVfM1wvLzl5lPfI71ou2Lqgos0sbSipI=; b=gmisqeZx9iMWY/zTMdtoC2pTLLlqcVUMTfbRKQnCEz8MtOgY+w3SWswkhY36UexusDHraeoyx WmsUP34C327CBPm7WNDl7+3AFDxIPKsiMhYwmcOSKdQLCwusVINyGm4 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Dynamic Capacity Devices (DCD) require event interrupts to process memory addition or removal. BIOS may have control over non-DCD event processing. DCD interrupt configuration needs to be separate from memory event interrupt configuration. Factor out event interrupt setting validation. Reviewed-by: Dave Jiang Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Li Ming Link: https://lore.kernel.org/all/663922b475e50_d54d72945b@dwillia2-xfh.jf.intel.com.notmuch/ [1] Suggested-by: Dan Williams Signed-off-by: Ira Weiny --- drivers/cxl/pci.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 8559b0eac011cadd49e67953b7560f49eedff94a..ac085a0b4881fc4f074d23f3606f9a3b7e70d05f 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -742,6 +742,21 @@ static bool cxl_event_int_is_fw(u8 setting) return mode == CXL_INT_FW; } +static bool cxl_event_validate_mem_policy(struct cxl_memdev_state *mds, + struct cxl_event_interrupt_policy *policy) +{ + if (cxl_event_int_is_fw(policy->info_settings) || + cxl_event_int_is_fw(policy->warn_settings) || + cxl_event_int_is_fw(policy->failure_settings) || + cxl_event_int_is_fw(policy->fatal_settings)) { + dev_err(mds->cxlds.dev, + "FW still in control of Event Logs despite _OSC settings\n"); + return false; + } + + return true; +} + static int cxl_event_config(struct pci_host_bridge *host_bridge, struct cxl_memdev_state *mds, bool irq_avail) { @@ -764,14 +779,8 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, if (rc) return rc; - if (cxl_event_int_is_fw(policy.info_settings) || - cxl_event_int_is_fw(policy.warn_settings) || - cxl_event_int_is_fw(policy.failure_settings) || - cxl_event_int_is_fw(policy.fatal_settings)) { - dev_err(mds->cxlds.dev, - "FW still in control of Event Logs despite _OSC settings\n"); + if (!cxl_event_validate_mem_policy(mds, &policy)) return -EBUSY; - } rc = cxl_event_config_msgnums(mds, &policy); if (rc) From patchwork Thu Nov 7 20:58:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867149 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 25A1421894D; Thu, 7 Nov 2024 20:59:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013152; cv=none; b=tPUBN0Z8b8ytegR3oIWXML/4KJltiGHzruGDzS1pd970ML2BlWIqZwsmRe3iQN+qez6oUH7SY68Tzc6RWg17yl9w5hp3WhvNg+436crHKwGn9zq9OlN4crQjyW4OZCnuD7UHjsjJZvkuw/OVTaFPweqrTU+QNQVD3TE6n4aKHg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013152; c=relaxed/simple; bh=uZmt4fu4lfzDks0d1cLXWcBK3mg+gUAha+y5C6U4TW0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dlPQq+tHhV3ZzxiEjdkK82ZAqeYABGR8kKePe1Hiz1LeeKgUC0sW+MEKOvlCRH7YWl8sZIyYIp0vreMQiILyVOYg/vjUZhh3ouzybChaxVjOYWkADU9+oZb57HjikCffxp82Jr9y79/bURxbpbNbvnqGAGqkrdVWGxkg7U82erQ= 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=IhW2O5lr; arc=none smtp.client-ip=198.175.65.11 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="IhW2O5lr" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013151; x=1762549151; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=uZmt4fu4lfzDks0d1cLXWcBK3mg+gUAha+y5C6U4TW0=; b=IhW2O5lrtcH/RKTkEiZ4knieaVsjjw1Jqrs7vczYbw94Qw5Gqve+4YP7 pNyW8diyd9B3+c64RXXzFO4iB7McQmBjjvY24CGKGYDSpQ+k6yDzAeYwQ 6NPdq7KmMrqjEKnlS5QUDusGIgWYjwPLtSkqV61kA3F83PhwyV5XXzclA 8teYpCVO3gLbYAUOnpFU5NRPa16iTarylPZ2FBTghGETWyovegJWCMIH/ 20jYkfnh+oYW2wIl+QW4JtBwIwdV7wuwI9gDRGvjr9jFU4bb6JBVAPs0B Asg3E/8AGMZKdUVhjrwLb+65eToVehCpFTNEVMtNqAK1ipK+HGrwZUN75 Q==; X-CSE-ConnectionGUID: GqaV6SjhSCCbPtSqbdZIvQ== X-CSE-MsgGUID: AtqKI/R/RrO371JrpmWmjQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441063" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441063" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:11 -0800 X-CSE-ConnectionGUID: ADnT5862RzCj+UlW8nVn1Q== X-CSE-MsgGUID: vIzvQEjuS6WaxM1cEjAaLQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746038" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:10 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:36 -0600 Subject: [PATCH v7 18/27] cxl/mem: Configure dynamic capacity interrupts Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-18-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=5723; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=ekPEkNyH6ChNNlyl/BpCbwpdWIPAnfjqx/gJRBCHRWQ=; b=1oJMPrk6u8Vo8axuHyzDlpG5/SnJSiOoHBUFQsFtbyI4n+b8DEDiMoQZS9yW9gxAw+lI6Xkcq Vd4B0lDIFSPDxwtpg6yRplazlKwe2qZIBg8bNnqKsFhSTrsFi6Z6oYD X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Dynamic Capacity Devices (DCD) support extent change notifications through the event log mechanism. The interrupt mailbox commands were extended in CXL 3.1 to support these notifications. Firmware can't configure DCD events to be FW controlled but can retain control of memory events. Configure DCD event log interrupts on devices supporting dynamic capacity. Disable DCD if interrupts are not supported. Care is taken to preserve the interrupt policy set by the FW if FW first has been selected by the BIOS. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Li Ming Reviewed-by: Fan Ni Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/cxlmem.h | 2 ++ drivers/cxl/pci.c | 73 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index bbdf52ac1d5cb5df82812c13ff50ca7cacfd0db6..863899b295b719b57638ee060e494e5cf2d639fd 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -226,7 +226,9 @@ struct cxl_event_interrupt_policy { u8 warn_settings; u8 failure_settings; u8 fatal_settings; + u8 dcd_settings; } __packed; +#define CXL_EVENT_INT_POLICY_BASE_SIZE 4 /* info, warn, failure, fatal */ /** * struct cxl_event_state - Event log driver state diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index ac085a0b4881fc4f074d23f3606f9a3b7e70d05f..13672b8cad5be4b5a955a91e9faaba0a0acd345a 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -672,23 +672,34 @@ static int cxl_event_get_int_policy(struct cxl_memdev_state *mds, } static int cxl_event_config_msgnums(struct cxl_memdev_state *mds, - struct cxl_event_interrupt_policy *policy) + struct cxl_event_interrupt_policy *policy, + bool native_cxl) { struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; + size_t size_in = CXL_EVENT_INT_POLICY_BASE_SIZE; struct cxl_mbox_cmd mbox_cmd; int rc; - *policy = (struct cxl_event_interrupt_policy) { - .info_settings = CXL_INT_MSI_MSIX, - .warn_settings = CXL_INT_MSI_MSIX, - .failure_settings = CXL_INT_MSI_MSIX, - .fatal_settings = CXL_INT_MSI_MSIX, - }; + /* memory event policy is left if FW has control */ + if (native_cxl) { + *policy = (struct cxl_event_interrupt_policy) { + .info_settings = CXL_INT_MSI_MSIX, + .warn_settings = CXL_INT_MSI_MSIX, + .failure_settings = CXL_INT_MSI_MSIX, + .fatal_settings = CXL_INT_MSI_MSIX, + .dcd_settings = 0, + }; + } + + if (cxl_dcd_supported(mds)) { + policy->dcd_settings = CXL_INT_MSI_MSIX; + size_in += sizeof(policy->dcd_settings); + } mbox_cmd = (struct cxl_mbox_cmd) { .opcode = CXL_MBOX_OP_SET_EVT_INT_POLICY, .payload_in = policy, - .size_in = sizeof(*policy), + .size_in = size_in, }; rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); @@ -735,6 +746,30 @@ static int cxl_event_irqsetup(struct cxl_memdev_state *mds, return 0; } +static int cxl_irqsetup(struct cxl_memdev_state *mds, + struct cxl_event_interrupt_policy *policy, + bool native_cxl) +{ + struct cxl_dev_state *cxlds = &mds->cxlds; + int rc; + + if (native_cxl) { + rc = cxl_event_irqsetup(mds, policy); + if (rc) + return rc; + } + + if (cxl_dcd_supported(mds)) { + rc = cxl_event_req_irq(cxlds, policy->dcd_settings); + if (rc) { + dev_err(cxlds->dev, "Failed to get interrupt for DCD event log\n"); + cxl_disable_dcd(mds); + } + } + + return 0; +} + static bool cxl_event_int_is_fw(u8 setting) { u8 mode = FIELD_GET(CXLDEV_EVENT_INT_MODE_MASK, setting); @@ -760,18 +795,26 @@ static bool cxl_event_validate_mem_policy(struct cxl_memdev_state *mds, static int cxl_event_config(struct pci_host_bridge *host_bridge, struct cxl_memdev_state *mds, bool irq_avail) { - struct cxl_event_interrupt_policy policy; + struct cxl_event_interrupt_policy policy = { 0 }; + bool native_cxl = host_bridge->native_cxl_error; int rc; /* * When BIOS maintains CXL error reporting control, it will process * event records. Only one agent can do so. + * + * If BIOS has control of events and DCD is not supported skip event + * configuration. */ - if (!host_bridge->native_cxl_error) + if (!native_cxl && !cxl_dcd_supported(mds)) return 0; if (!irq_avail) { dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n"); + if (cxl_dcd_supported(mds)) { + dev_info(mds->cxlds.dev, "DCD requires interrupts, disable DCD\n"); + cxl_disable_dcd(mds); + } return 0; } @@ -779,10 +822,10 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, if (rc) return rc; - if (!cxl_event_validate_mem_policy(mds, &policy)) + if (native_cxl && !cxl_event_validate_mem_policy(mds, &policy)) return -EBUSY; - rc = cxl_event_config_msgnums(mds, &policy); + rc = cxl_event_config_msgnums(mds, &policy, native_cxl); if (rc) return rc; @@ -790,12 +833,16 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, if (rc) return rc; - rc = cxl_event_irqsetup(mds, &policy); + rc = cxl_irqsetup(mds, &policy, native_cxl); if (rc) return rc; cxl_mem_get_event_records(mds, CXLDEV_EVENT_STATUS_ALL); + dev_dbg(mds->cxlds.dev, "Event config : %s DCD %s\n", + native_cxl ? "OS" : "BIOS", + cxl_dcd_supported(mds) ? "supported" : "not supported"); + return 0; } From patchwork Thu Nov 7 20:58:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867150 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 F10FF224429; Thu, 7 Nov 2024 20:59:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013154; cv=none; b=VPhD+Sl2w0i1bpsKS9qMfo/ZQ6BKUdkfU+6B8+af5SeJWgujkBgtwkmsXgKgHh2Gh2TgSjisy7QPqUmnBuVJpwyD7fWsafA6HeRKChc2GQEQuzBE+RnvQt2cD/LRy4kMz5H038+i4lhUR7UJThC5ox0+VG8F7Bl09zgmIWLgs+Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013154; c=relaxed/simple; bh=K+k0tXosQggrTMURAffVjBncyyVcL5TE5nyLNi6NZqU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DMfcnul4jNfz6EPtBq9nxbygzNZ/xtFripYXzQlzeHJHJFYp/IrhzJR/TVxFseiqRUn3QlqobpbX1wcTDL7LoRpJQKfHQtZFx5+acrdY1seWbaAXBaOMlDuQwZETiVWNg+ClxxuLEZqZg2fPsrxQsKIHCeqPW1gbnSgKDvvZ3DY= 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=ESF++LFt; arc=none smtp.client-ip=198.175.65.11 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="ESF++LFt" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013153; x=1762549153; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=K+k0tXosQggrTMURAffVjBncyyVcL5TE5nyLNi6NZqU=; b=ESF++LFt3aJ+EdI5UzH3XUiWf1J4E8MvgF4L1vgierV+I0Puw9ghjN7C Fc8EiZL+syhNKtl3PAZD7Ul9MVT5Z1G5aioEl0DDFEBAZtNXQaUFnyEtm QKObPpHc4xK607aqiWziK9FFoP7oBoJLL8JI/fhrRRX5PfaOi3gAVMBfg nWVlNX54TXZ89yeygAkecT+l/eoQ9T5FZm8/a5E7+Dzvkq/f+X47RcIFu ijj/J0O5d8JrHg+bL9AUTmsbN3Y5E+bHavVCl06P4RI79PtNZMzq8V5VZ Ge2uHY80rJ3WvMt2wROIBqXhuRTSIvsyluX7jKyEEWLREFbKWiceHeq3e w==; X-CSE-ConnectionGUID: /OjuNIb2TbeVRqCP4z8DdA== X-CSE-MsgGUID: Sqx0EfSPQaCDsIFB+XUkaw== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441072" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441072" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:13 -0800 X-CSE-ConnectionGUID: AOI0WCNFSHStcmVZOIss1A== X-CSE-MsgGUID: XnxElBI2SiKpqGAdyc2QvA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746044" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:12 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:37 -0600 Subject: [PATCH v7 19/27] cxl/core: Return endpoint decoder information from region search Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-19-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=4661; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=K+k0tXosQggrTMURAffVjBncyyVcL5TE5nyLNi6NZqU=; b=XxpkfhH/oNIRvtsu/9kGbwI9gPuqSbhtuqejYpLYvXTtHHRZzufy27FEPVjHJnW8Qd1ppqGcq SLvGTnUaad4CVY0l+KvZ9w4KiHDjF6IUBwBEp2aCb0BRBQZN9mZ6qf0 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= cxl_dpa_to_region() finds the region from a tuple. The search involves finding the device endpoint decoder as well. Dynamic capacity extent processing uses the endpoint decoder HPA information to calculate the HPA offset. In addition, well behaved extents should be contained within an endpoint decoder. Return the endpoint decoder found to be used in subsequent DCD code. Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Reviewed-by: Dave Jiang Reviewed-by: Li Ming Reviewed-by: Alison Schofield Signed-off-by: Ira Weiny --- drivers/cxl/core/core.h | 6 ++++-- drivers/cxl/core/mbox.c | 2 +- drivers/cxl/core/memdev.c | 4 ++-- drivers/cxl/core/region.c | 8 +++++++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 5d6fe7ab0a78cddb01c7e0d63ed55c36879c4cef..94ee06cfbdca07b50130299dfe0dd6546e7b9dac 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -39,7 +39,8 @@ void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); int cxl_region_init(void); void cxl_region_exit(void); int cxl_get_poison_by_endpoint(struct cxl_port *port); -struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa); +struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa, + struct cxl_endpoint_decoder **cxled); u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa); @@ -50,7 +51,8 @@ static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, return ULLONG_MAX; } static inline -struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) +struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa, + struct cxl_endpoint_decoder **cxled) { return NULL; } diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index a4b5cb61b4e6f9b17e3e3e0cce356b0ac9f960d0..a06137d95c6822192fb279068abf964f98f0a335 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -916,7 +916,7 @@ void cxl_event_trace_record(const struct cxl_memdev *cxlmd, guard(rwsem_read)(&cxl_dpa_rwsem); dpa = le64_to_cpu(evt->media_hdr.phys_addr) & CXL_DPA_MASK; - cxlr = cxl_dpa_to_region(cxlmd, dpa); + cxlr = cxl_dpa_to_region(cxlmd, dpa, NULL); if (cxlr) hpa = cxl_dpa_to_hpa(cxlr, cxlmd, dpa); diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 857a9dd88b20291116d20b9c0bbe9e7961f4491f..f0e68264af7b4aa19e44c5a5e01c0a0614b0f27e 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -313,7 +313,7 @@ int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa) if (rc) goto out; - cxlr = cxl_dpa_to_region(cxlmd, dpa); + cxlr = cxl_dpa_to_region(cxlmd, dpa, NULL); if (cxlr) dev_warn_once(cxl_mbox->host, "poison inject dpa:%#llx region: %s\n", dpa, @@ -377,7 +377,7 @@ int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa) if (rc) goto out; - cxlr = cxl_dpa_to_region(cxlmd, dpa); + cxlr = cxl_dpa_to_region(cxlmd, dpa, NULL); if (cxlr) dev_warn_once(cxl_mbox->host, "poison clear dpa:%#llx region: %s\n", dpa, diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 34a6f447e75b18e6a1c8c27250a3e425bd0cc515..a0c181cc33e4988e5c841d5b009d3d4aed5606c1 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -2827,6 +2827,7 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) struct cxl_dpa_to_region_context { struct cxl_region *cxlr; u64 dpa; + struct cxl_endpoint_decoder *cxled; }; static int __cxl_dpa_to_region(struct device *dev, void *arg) @@ -2860,11 +2861,13 @@ static int __cxl_dpa_to_region(struct device *dev, void *arg) dev_name(dev)); ctx->cxlr = cxlr; + ctx->cxled = cxled; return 1; } -struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) +struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa, + struct cxl_endpoint_decoder **cxled) { struct cxl_dpa_to_region_context ctx; struct cxl_port *port; @@ -2876,6 +2879,9 @@ struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa) if (port && is_cxl_endpoint(port) && cxl_num_decoders_committed(port)) device_for_each_child(&port->dev, &ctx, __cxl_dpa_to_region); + if (cxled) + *cxled = ctx.cxled; + return ctx.cxlr; } From patchwork Thu Nov 7 20:58:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867152 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 D047A224B4A; Thu, 7 Nov 2024 20:59:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013160; cv=none; b=fW0zT6MLZwCKjU1YhCKCwnenSmHkaJKOmS9plOlhq0K9Pco8BabNKcqsUznqFyTheJAsb2T0fCSr2nq7fYrpkxEOyNmLMeZVd2hwcT7N/t64W+1XgJBI3RYT6N2VtP4SlykxmD2zcg4tv/I5EOe18pekZK02rctkh0gRdPGsQr4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013160; c=relaxed/simple; bh=RA7/V8d3+/ZG+TEho2L2jAdCPkNmfQB02sBeilyCcIg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JteZJf1/kUsHwl0jDfAp+D0L3/FBOfSduSNTrHiAfRGt7jdjYyAPRwZa2/Qh2i9RslIcj5LZcs2XTB4q70NzrSf6V8x9ISRDXKGN7PeD6dCh7w8dc7WbDKO0aHSO/Psk5NA7pZKebs+s2hSW0roF4OyPffeGqcPpSz0TctyxFXA= 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=Z1YKfFVO; arc=none smtp.client-ip=198.175.65.11 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="Z1YKfFVO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013156; x=1762549156; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=RA7/V8d3+/ZG+TEho2L2jAdCPkNmfQB02sBeilyCcIg=; b=Z1YKfFVORqB+MXl7AhYYOTQ4yth79sUM2uXTmvlHvXDaur3bcS5aexML gbH85h6uRhGodRdaCxqlTSe9u/+5Q9fY1DYQzrKaLHXvmlTPa/RWBASl5 hl+OXddAoLIfoZ0R//jp30FIPnFS6B1QUwLZJNgKipufpVtqmOI4ZdShA W0hzchVR8AjSw/1LBZrmXTBy04LVM4Y6Xfi6OpeuiQo+cfKWSBUXd0nz5 gySPiLXxhZgTOqVnkVX/WS+uTjVOcrZstvYHqNoJql+d1p86+IgRnpR7q KmIhM1POxgiiqumaauu8jSZH3DRB2fIi0h7Js/tH3l1DPlmchbwgjw08Y g==; X-CSE-ConnectionGUID: /uy0RHFzQVafECduWtkNUQ== X-CSE-MsgGUID: FIhLAnjgTmuI9+AR0kocCQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441080" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441080" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:15 -0800 X-CSE-ConnectionGUID: mFPyhTdPQXmy6t7BVxuRBw== X-CSE-MsgGUID: syCcAiElTu2BtbUEZR4XqQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746050" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:14 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:38 -0600 Subject: [PATCH v7 20/27] cxl/extent: Process DCD events and realize region extents Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-20-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org, Li Ming X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=36317; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=c4CLS8Mp66GKk4V7YeHPJYH7JdimQ+hnahguk6DBLcg=; b=wwT+Q+BVecmRBOnFwuvCRhEqBv1h2PaF7Z1T3CTgZQtfI6E0qi4AbKeoXCBvUae7u6qC+hm2Q MVO+iDejBTYCoBPbPPXUF47qLtA2Gwe+Nyc5Grg/iy9tGrNlQOMpf2h X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh A dynamic capacity device (DCD) sends events to signal the host for changes in the availability of Dynamic Capacity (DC) memory. These events contain extents describing a DPA range and meta data for memory to be added or removed. Events may be sent from the device at any time. Three types of events can be signaled, Add, Release, and Force Release. On add, the host may accept or reject the memory being offered. If no region exists, or the extent is invalid, the extent should be rejected. Add extent events may be grouped by a 'more' bit which indicates those extents should be processed as a group. On remove, the host can delay the response until the host is safely not using the memory. If no region exists the release can be sent immediately. The host may also release extents (or partial extents) at any time. Thus the 'more' bit grouping of release events is of less value and can be ignored in favor of sending multiple release capacity responses for groups of release events. Force removal is intended as a mechanism between the FM and the device and intended only when the host is unresponsive, out of sync, or otherwise broken. Purposely ignore force removal events. Regions are made up of one or more devices which may be surfacing memory to the host. Once all devices in a region have surfaced an extent the region can expose a corresponding extent for the user to consume. Without interleaving a device extent forms a 1:1 relationship with the region extent. Immediately surface a region extent upon getting a device extent. Per the specification the device is allowed to offer or remove extents at any time. However, anticipated use cases can expect extents to be offered, accepted, and removed in well defined chunks. Simplify extent tracking with the following restrictions. 1) Flag for removal any extent which overlaps a requested release range. 2) Refuse the offer of extents which overlap already accepted memory ranges. 3) Accept again a range which has already been accepted by the host. Eating duplicates serves three purposes. First, this simplifies the code if the device should get out of sync with the host. And it should be safe to acknowledge the extent again. Second, this simplifies the code to process existing extents if the extent list should change while the extent list is being read. Third, duplicates for a given region which are seen during a race between the hardware surfacing an extent and the cxl dax driver scanning for existing extents will be ignored. NOTE: Processing existing extents is done in a later patch. Management of the region extent devices must be synchronized with potential uses of the memory within the DAX layer. Create region extent devices as children of the cxl_dax_region device such that the DAX region driver can co-drive them and synchronize with the DAX layer. Synchronization and management is handled in a subsequent patch. Tag support within the DAX layer is not yet supported. To maintain compatibility legacy DAX/region processing only tags with a value of 0 are allowed. This defines existing DAX devices as having a 0 tag which makes the most logical sense as a default. Process DCD events and create region devices. Reviewed-by: Dave Jiang Reviewed-by: Li Ming Reviewed-by: Jonathan Cameron Signed-off-by: Navneet Singh Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- Changes: [Ming: Fix setting the more flag] --- drivers/cxl/core/Makefile | 2 +- drivers/cxl/core/core.h | 13 ++ drivers/cxl/core/extent.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/mbox.c | 295 +++++++++++++++++++++++++++++++++++- drivers/cxl/core/region.c | 3 + drivers/cxl/cxl.h | 53 ++++++- drivers/cxl/cxlmem.h | 27 ++++ include/cxl/event.h | 32 ++++ tools/testing/cxl/Kbuild | 3 +- 9 files changed, 795 insertions(+), 4 deletions(-) diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 9259bcc6773c804ccace2478c9f6f09267b48c9d..3b812515e72536aee5cd305e1ffabfd5a8bd296c 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -15,4 +15,4 @@ cxl_core-y += hdm.o cxl_core-y += pmu.o cxl_core-y += cdat.o cxl_core-$(CONFIG_TRACING) += trace.o -cxl_core-$(CONFIG_CXL_REGION) += region.o +cxl_core-$(CONFIG_CXL_REGION) += region.o extent.o diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 94ee06cfbdca07b50130299dfe0dd6546e7b9dac..0eccdd0b9261467fe762aa665776c87c5cb9ce24 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -44,12 +44,24 @@ struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa, u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa); +int cxl_add_extent(struct cxl_memdev_state *mds, struct cxl_extent *extent); +int cxl_rm_extent(struct cxl_memdev_state *mds, struct cxl_extent *extent); #else static inline u64 cxl_dpa_to_hpa(struct cxl_region *cxlr, const struct cxl_memdev *cxlmd, u64 dpa) { return ULLONG_MAX; } +static inline int cxl_add_extent(struct cxl_memdev_state *mds, + struct cxl_extent *extent) +{ + return 0; +} +static inline int cxl_rm_extent(struct cxl_memdev_state *mds, + struct cxl_extent *extent) +{ + return 0; +} static inline struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa, struct cxl_endpoint_decoder **cxled) @@ -123,5 +135,6 @@ int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, bool cxl_need_node_perf_attrs_update(int nid); int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port, struct access_coordinate *c); +void memdev_release_extent(struct cxl_memdev_state *mds, struct range *range); #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c new file mode 100644 index 0000000000000000000000000000000000000000..bb12abe4792bcadd2442de3c21bf5ce4d48edf06 --- /dev/null +++ b/drivers/cxl/core/extent.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2024 Intel Corporation. All rights reserved. */ + +#include +#include + +#include "core.h" + +static void cxled_release_extent(struct cxl_endpoint_decoder *cxled, + struct cxled_extent *ed_extent) +{ + struct cxl_memdev_state *mds = cxled_to_mds(cxled); + struct device *dev = &cxled->cxld.dev; + + dev_dbg(dev, "Remove extent [range 0x%016llx-0x%016llx] (%pU)\n", + ed_extent->dpa_range.start, ed_extent->dpa_range.end, + ed_extent->tag); + memdev_release_extent(mds, &ed_extent->dpa_range); + kfree(ed_extent); +} + +static void free_region_extent(struct region_extent *region_extent) +{ + struct cxled_extent *ed_extent; + unsigned long index; + + /* + * Remove from each endpoint decoder the extent which backs this region + * extent + */ + xa_for_each(®ion_extent->decoder_extents, index, ed_extent) + cxled_release_extent(ed_extent->cxled, ed_extent); + xa_destroy(®ion_extent->decoder_extents); + ida_free(®ion_extent->cxlr_dax->extent_ida, region_extent->dev.id); + kfree(region_extent); +} + +static void region_extent_release(struct device *dev) +{ + struct region_extent *region_extent = to_region_extent(dev); + + free_region_extent(region_extent); +} + +static const struct device_type region_extent_type = { + .name = "extent", + .release = region_extent_release, +}; + +bool is_region_extent(struct device *dev) +{ + return dev->type == ®ion_extent_type; +} +EXPORT_SYMBOL_NS_GPL(is_region_extent, CXL); + +static void region_extent_unregister(void *ext) +{ + struct region_extent *region_extent = ext; + + dev_dbg(®ion_extent->dev, "DAX region rm extent HPA [range 0x%016llx-0x%016llx]\n", + region_extent->hpa_range.start, region_extent->hpa_range.end); + device_unregister(®ion_extent->dev); +} + +static void region_rm_extent(struct region_extent *region_extent) +{ + struct device *region_dev = region_extent->dev.parent; + + devm_release_action(region_dev, region_extent_unregister, region_extent); +} + +static struct region_extent * +alloc_region_extent(struct cxl_dax_region *cxlr_dax, struct range *hpa_range, u8 *tag) +{ + int id; + + struct region_extent *region_extent __free(kfree) = + kzalloc(sizeof(*region_extent), GFP_KERNEL); + if (!region_extent) + return ERR_PTR(-ENOMEM); + + id = ida_alloc(&cxlr_dax->extent_ida, GFP_KERNEL); + if (id < 0) + return ERR_PTR(-ENOMEM); + + region_extent->hpa_range = *hpa_range; + region_extent->cxlr_dax = cxlr_dax; + import_uuid(®ion_extent->tag, tag); + region_extent->dev.id = id; + xa_init(®ion_extent->decoder_extents); + return no_free_ptr(region_extent); +} + +static int online_region_extent(struct region_extent *region_extent) +{ + struct cxl_dax_region *cxlr_dax = region_extent->cxlr_dax; + struct device *dev = ®ion_extent->dev; + int rc; + + device_initialize(dev); + device_set_pm_not_required(dev); + dev->parent = &cxlr_dax->dev; + dev->type = ®ion_extent_type; + rc = dev_set_name(dev, "extent%d.%d", cxlr_dax->cxlr->id, dev->id); + if (rc) + goto err; + + rc = device_add(dev); + if (rc) + goto err; + + dev_dbg(dev, "region extent HPA [range 0x%016llx-0x%016llx]\n", + region_extent->hpa_range.start, region_extent->hpa_range.end); + return devm_add_action_or_reset(&cxlr_dax->dev, region_extent_unregister, + region_extent); + +err: + dev_err(&cxlr_dax->dev, "Failed to initialize region extent HPA [range 0x%016llx-0x%016llx]\n", + region_extent->hpa_range.start, region_extent->hpa_range.end); + + put_device(dev); + return rc; +} + +struct match_data { + struct cxl_endpoint_decoder *cxled; + struct range *new_range; +}; + +static int match_contains(struct device *dev, void *data) +{ + struct region_extent *region_extent = to_region_extent(dev); + struct match_data *md = data; + struct cxled_extent *entry; + unsigned long index; + + if (!region_extent) + return 0; + + xa_for_each(®ion_extent->decoder_extents, index, entry) { + if (md->cxled == entry->cxled && + range_contains(&entry->dpa_range, md->new_range)) + return 1; + } + return 0; +} + +static bool extents_contain(struct cxl_dax_region *cxlr_dax, + struct cxl_endpoint_decoder *cxled, + struct range *new_range) +{ + struct match_data md = { + .cxled = cxled, + .new_range = new_range, + }; + + struct device *extent_device __free(put_device) + = device_find_child(&cxlr_dax->dev, &md, match_contains); + if (!extent_device) + return false; + + return true; +} + +static int match_overlaps(struct device *dev, void *data) +{ + struct region_extent *region_extent = to_region_extent(dev); + struct match_data *md = data; + struct cxled_extent *entry; + unsigned long index; + + if (!region_extent) + return 0; + + xa_for_each(®ion_extent->decoder_extents, index, entry) { + if (md->cxled == entry->cxled && + range_overlaps(&entry->dpa_range, md->new_range)) + return 1; + } + + return 0; +} + +static bool extents_overlap(struct cxl_dax_region *cxlr_dax, + struct cxl_endpoint_decoder *cxled, + struct range *new_range) +{ + struct match_data md = { + .cxled = cxled, + .new_range = new_range, + }; + + struct device *extent_device __free(put_device) + = device_find_child(&cxlr_dax->dev, &md, match_overlaps); + if (!extent_device) + return false; + + return true; +} + +static void calc_hpa_range(struct cxl_endpoint_decoder *cxled, + struct cxl_dax_region *cxlr_dax, + struct range *dpa_range, + struct range *hpa_range) +{ + resource_size_t dpa_offset, hpa; + + dpa_offset = dpa_range->start - cxled->dpa_res->start; + hpa = cxled->cxld.hpa_range.start + dpa_offset; + + hpa_range->start = hpa - cxlr_dax->hpa_range.start; + hpa_range->end = hpa_range->start + range_len(dpa_range) - 1; +} + +static int cxlr_rm_extent(struct device *dev, void *data) +{ + struct region_extent *region_extent = to_region_extent(dev); + struct range *region_hpa_range = data; + + if (!region_extent) + return 0; + + /* + * Any extent which 'touches' the released range is removed. + */ + if (range_overlaps(region_hpa_range, ®ion_extent->hpa_range)) { + dev_dbg(dev, "Remove region extent HPA [range 0x%016llx-0x%016llx]\n", + region_extent->hpa_range.start, region_extent->hpa_range.end); + region_rm_extent(region_extent); + } + return 0; +} + +int cxl_rm_extent(struct cxl_memdev_state *mds, struct cxl_extent *extent) +{ + u64 start_dpa = le64_to_cpu(extent->start_dpa); + struct cxl_memdev *cxlmd = mds->cxlds.cxlmd; + struct cxl_endpoint_decoder *cxled; + struct range hpa_range, dpa_range; + struct cxl_region *cxlr; + + dpa_range = (struct range) { + .start = start_dpa, + .end = start_dpa + le64_to_cpu(extent->length) - 1, + }; + + guard(rwsem_read)(&cxl_region_rwsem); + cxlr = cxl_dpa_to_region(cxlmd, start_dpa, &cxled); + if (!cxlr) { + /* + * No region can happen here for a few reasons: + * + * 1) Extents were accepted and the host crashed/rebooted + * leaving them in an accepted state. On reboot the host + * has not yet created a region to own them. + * + * 2) Region destruction won the race with the device releasing + * all the extents. Here the release will be a duplicate of + * the one sent via region destruction. + * + * 3) The device is confused and releasing extents for which no + * region ever existed. + * + * In all these cases make sure the device knows we are not + * using this extent. + */ + memdev_release_extent(mds, &dpa_range); + return -ENXIO; + } + + calc_hpa_range(cxled, cxlr->cxlr_dax, &dpa_range, &hpa_range); + + /* Remove region extents which overlap */ + return device_for_each_child(&cxlr->cxlr_dax->dev, &hpa_range, + cxlr_rm_extent); +} + +static int cxlr_add_extent(struct cxl_dax_region *cxlr_dax, + struct cxl_endpoint_decoder *cxled, + struct cxled_extent *ed_extent) +{ + struct region_extent *region_extent; + struct range hpa_range; + int rc; + + calc_hpa_range(cxled, cxlr_dax, &ed_extent->dpa_range, &hpa_range); + + region_extent = alloc_region_extent(cxlr_dax, &hpa_range, ed_extent->tag); + if (IS_ERR(region_extent)) + return PTR_ERR(region_extent); + + rc = xa_insert(®ion_extent->decoder_extents, (unsigned long)ed_extent, + ed_extent, GFP_KERNEL); + if (rc) { + free_region_extent(region_extent); + return rc; + } + + /* device model handles freeing region_extent */ + return online_region_extent(region_extent); +} + +/* Callers are expected to ensure cxled has been attached to a region */ +int cxl_add_extent(struct cxl_memdev_state *mds, struct cxl_extent *extent) +{ + u64 start_dpa = le64_to_cpu(extent->start_dpa); + struct cxl_memdev *cxlmd = mds->cxlds.cxlmd; + struct cxl_endpoint_decoder *cxled; + struct range ed_range, ext_range; + struct cxl_dax_region *cxlr_dax; + struct cxled_extent *ed_extent; + struct cxl_region *cxlr; + struct device *dev; + + ext_range = (struct range) { + .start = start_dpa, + .end = start_dpa + le64_to_cpu(extent->length) - 1, + }; + + guard(rwsem_read)(&cxl_region_rwsem); + cxlr = cxl_dpa_to_region(cxlmd, start_dpa, &cxled); + if (!cxlr) + return -ENXIO; + + cxlr_dax = cxled->cxld.region->cxlr_dax; + dev = &cxled->cxld.dev; + ed_range = (struct range) { + .start = cxled->dpa_res->start, + .end = cxled->dpa_res->end, + }; + + dev_dbg(&cxled->cxld.dev, "Checking ED (%pr) for extent [range 0x%016llx-0x%016llx]\n", + cxled->dpa_res, ext_range.start, ext_range.end); + + if (!range_contains(&ed_range, &ext_range)) { + dev_err_ratelimited(dev, + "DC extent DPA [range 0x%016llx-0x%016llx] (%pU) is not fully in ED [range 0x%016llx-0x%016llx]\n", + ext_range.start, ext_range.end, extent->tag, + ed_range.start, ed_range.end); + return -ENXIO; + } + + /* + * Allowing duplicates or extents which are already in an accepted + * range simplifies extent processing, especially when dealing with the + * cxl dax driver scanning for existing extents. + */ + if (extents_contain(cxlr_dax, cxled, &ext_range)) { + dev_warn_ratelimited(dev, + "Extent [range 0x%016llx-0x%016llx] exists; accept again\n", + ext_range.start, ext_range.end); + return 0; + } + + if (extents_overlap(cxlr_dax, cxled, &ext_range)) + return -ENXIO; + + ed_extent = kzalloc(sizeof(*ed_extent), GFP_KERNEL); + if (!ed_extent) + return -ENOMEM; + + ed_extent->cxled = cxled; + ed_extent->dpa_range = ext_range; + memcpy(ed_extent->tag, extent->tag, CXL_EXTENT_TAG_LEN); + + dev_dbg(dev, "Add extent [range 0x%016llx-0x%016llx] (%pU)\n", + ed_extent->dpa_range.start, ed_extent->dpa_range.end, + ed_extent->tag); + + return cxlr_add_extent(cxlr_dax, cxled, ed_extent); +} diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index a06137d95c6822192fb279068abf964f98f0a335..61d406d19bf777a3921dbb3cc1213d341d8dea4c 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -889,6 +889,59 @@ int cxl_enumerate_cmds(struct cxl_memdev_state *mds) } EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL); +static u8 zero_tag[CXL_EXTENT_TAG_LEN] = { 0 }; + +static int cxl_validate_extent(struct cxl_memdev_state *mds, + struct cxl_extent *extent) +{ + u64 start = le64_to_cpu(extent->start_dpa); + u64 length = le64_to_cpu(extent->length); + struct device *dev = mds->cxlds.dev; + + struct range ext_range = (struct range){ + .start = start, + .end = start + length - 1, + }; + + if (le16_to_cpu(extent->shared_extn_seq) != 0) { + dev_err_ratelimited(dev, + "DC extent DPA [range 0x%016llx-0x%016llx] (%pU) can not be shared\n", + ext_range.start, ext_range.end, + extent->tag); + return -ENXIO; + } + + if (memcmp(extent->tag, zero_tag, CXL_EXTENT_TAG_LEN)) { + dev_err_ratelimited(dev, + "DC extent DPA [range 0x%016llx-0x%016llx] (%pU); tags not supported\n", + ext_range.start, ext_range.end, + extent->tag); + return -ENXIO; + } + + /* Extents must not cross DC region boundary's */ + for (int i = 0; i < mds->nr_dc_region; i++) { + struct cxl_dc_region_info *dcr = &mds->dc_region[i]; + struct range region_range = (struct range) { + .start = dcr->base, + .end = dcr->base + dcr->decode_len - 1, + }; + + if (range_contains(®ion_range, &ext_range)) { + dev_dbg(dev, "DC extent DPA [range 0x%016llx-0x%016llx] (DCR:%d:%#llx)(%pU)\n", + ext_range.start, ext_range.end, i, start - dcr->base, + extent->tag); + return 0; + } + } + + dev_err_ratelimited(dev, + "DC extent DPA [range 0x%016llx-0x%016llx] (%pU) is not in any DC region\n", + ext_range.start, ext_range.end, + extent->tag); + return -ENXIO; +} + void cxl_event_trace_record(const struct cxl_memdev *cxlmd, enum cxl_event_log_type type, enum cxl_event_type event_type, @@ -1017,6 +1070,224 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds, return rc; } +static int send_one_response(struct cxl_mailbox *cxl_mbox, + struct cxl_mbox_dc_response *response, + int opcode, u32 extent_list_size, u8 flags) +{ + struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = opcode, + .size_in = struct_size(response, extent_list, extent_list_size), + .payload_in = response, + }; + + response->extent_list_size = cpu_to_le32(extent_list_size); + response->flags = flags; + return cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); +} + +static int cxl_send_dc_response(struct cxl_memdev_state *mds, int opcode, + struct xarray *extent_array, int cnt) +{ + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; + struct cxl_mbox_dc_response *p; + struct cxl_extent *extent; + unsigned long index; + u32 pl_index; + + size_t pl_size = struct_size(p, extent_list, cnt); + u32 max_extents = cnt; + + /* May have to use more bit on response. */ + if (pl_size > cxl_mbox->payload_size) { + max_extents = (cxl_mbox->payload_size - sizeof(*p)) / + sizeof(struct updated_extent_list); + pl_size = struct_size(p, extent_list, max_extents); + } + + struct cxl_mbox_dc_response *response __free(kfree) = + kzalloc(pl_size, GFP_KERNEL); + if (!response) + return -ENOMEM; + + if (cnt == 0) + return send_one_response(cxl_mbox, response, opcode, 0, 0); + + pl_index = 0; + xa_for_each(extent_array, index, extent) { + response->extent_list[pl_index].dpa_start = extent->start_dpa; + response->extent_list[pl_index].length = extent->length; + pl_index++; + + if (pl_index == max_extents) { + u8 flags = 0; + int rc; + + if (pl_index < cnt) + flags |= CXL_DCD_EVENT_MORE; + rc = send_one_response(cxl_mbox, response, opcode, + pl_index, flags); + if (rc) + return rc; + cnt -= pl_index; + pl_index = 0; + } + } + + if (!pl_index) /* nothing more to do */ + return 0; + return send_one_response(cxl_mbox, response, opcode, pl_index, 0); +} + +void memdev_release_extent(struct cxl_memdev_state *mds, struct range *range) +{ + struct device *dev = mds->cxlds.dev; + struct xarray extent_list; + + struct cxl_extent extent = { + .start_dpa = cpu_to_le64(range->start), + .length = cpu_to_le64(range_len(range)), + }; + + dev_dbg(dev, "Release response dpa [range 0x%016llx-0x%016llx]\n", + range->start, range->end); + + xa_init(&extent_list); + if (xa_insert(&extent_list, 0, &extent, GFP_KERNEL)) { + dev_dbg(dev, "Failed to release [range 0x%016llx-0x%016llx]\n", + range->start, range->end); + goto destroy; + } + + if (cxl_send_dc_response(mds, CXL_MBOX_OP_RELEASE_DC, &extent_list, 1)) + dev_dbg(dev, "Failed to release [range 0x%016llx-0x%016llx]\n", + range->start, range->end); + +destroy: + xa_destroy(&extent_list); +} + +static int validate_add_extent(struct cxl_memdev_state *mds, + struct cxl_extent *extent) +{ + int rc; + + rc = cxl_validate_extent(mds, extent); + if (rc) + return rc; + + return cxl_add_extent(mds, extent); +} + +static int cxl_add_pending(struct cxl_memdev_state *mds) +{ + struct device *dev = mds->cxlds.dev; + struct cxl_extent *extent; + unsigned long cnt = 0; + unsigned long index; + int rc; + + xa_for_each(&mds->pending_extents, index, extent) { + if (validate_add_extent(mds, extent)) { + /* + * Any extents which are to be rejected are omitted from + * the response. An empty response means all are + * rejected. + */ + dev_dbg(dev, "unconsumed DC extent DPA:%#llx LEN:%#llx\n", + le64_to_cpu(extent->start_dpa), + le64_to_cpu(extent->length)); + xa_erase(&mds->pending_extents, index); + kfree(extent); + continue; + } + cnt++; + } + rc = cxl_send_dc_response(mds, CXL_MBOX_OP_ADD_DC_RESPONSE, + &mds->pending_extents, cnt); + xa_for_each(&mds->pending_extents, index, extent) { + xa_erase(&mds->pending_extents, index); + kfree(extent); + } + return rc; +} + +static int handle_add_event(struct cxl_memdev_state *mds, + struct cxl_event_dcd *event) +{ + struct device *dev = mds->cxlds.dev; + struct cxl_extent *extent; + + extent = kmemdup(&event->extent, sizeof(*extent), GFP_KERNEL); + if (!extent) + return -ENOMEM; + + if (xa_insert(&mds->pending_extents, (unsigned long)extent, extent, + GFP_KERNEL)) { + kfree(extent); + return -ENOMEM; + } + + if (event->flags & CXL_DCD_EVENT_MORE) { + dev_dbg(dev, "more bit set; delay the surfacing of extent\n"); + return 0; + } + + /* extents are removed and free'ed in cxl_add_pending() */ + return cxl_add_pending(mds); +} + +static char *cxl_dcd_evt_type_str(u8 type) +{ + switch (type) { + case DCD_ADD_CAPACITY: + return "add"; + case DCD_RELEASE_CAPACITY: + return "release"; + case DCD_FORCED_CAPACITY_RELEASE: + return "force release"; + default: + break; + } + + return ""; +} + +static void cxl_handle_dcd_event_records(struct cxl_memdev_state *mds, + struct cxl_event_record_raw *raw_rec) +{ + struct cxl_event_dcd *event = &raw_rec->event.dcd; + struct cxl_extent *extent = &event->extent; + struct device *dev = mds->cxlds.dev; + uuid_t *id = &raw_rec->id; + int rc; + + if (!uuid_equal(id, &CXL_EVENT_DC_EVENT_UUID)) + return; + + dev_dbg(dev, "DCD event %s : DPA:%#llx LEN:%#llx\n", + cxl_dcd_evt_type_str(event->event_type), + le64_to_cpu(extent->start_dpa), le64_to_cpu(extent->length)); + + switch (event->event_type) { + case DCD_ADD_CAPACITY: + rc = handle_add_event(mds, event); + break; + case DCD_RELEASE_CAPACITY: + rc = cxl_rm_extent(mds, &event->extent); + break; + case DCD_FORCED_CAPACITY_RELEASE: + dev_err_ratelimited(dev, "Forced release event ignored.\n"); + rc = 0; + break; + default: + rc = -EINVAL; + break; + } + + if (rc) + dev_err_ratelimited(dev, "dcd event failed: %d\n", rc); +} + static void cxl_mem_get_records_log(struct cxl_memdev_state *mds, enum cxl_event_log_type type) { @@ -1053,9 +1324,13 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds, if (!nr_rec) break; - for (i = 0; i < nr_rec; i++) + for (i = 0; i < nr_rec; i++) { __cxl_event_trace_record(cxlmd, type, &payload->records[i]); + if (type == CXL_EVENT_TYPE_DCD) + cxl_handle_dcd_event_records(mds, + &payload->records[i]); + } if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW) trace_cxl_overflow(cxlmd, type, payload); @@ -1087,6 +1362,8 @@ void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status) { dev_dbg(mds->cxlds.dev, "Reading event logs: %x\n", status); + if (cxl_dcd_supported(mds) && (status & CXLDEV_EVENT_STATUS_DCD)) + cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_DCD); if (status & CXLDEV_EVENT_STATUS_FATAL) cxl_mem_get_records_log(mds, CXL_EVENT_TYPE_FATAL); if (status & CXLDEV_EVENT_STATUS_FAIL) @@ -1632,9 +1909,21 @@ int cxl_mailbox_init(struct cxl_mailbox *cxl_mbox, struct device *host) } EXPORT_SYMBOL_NS_GPL(cxl_mailbox_init, CXL); +static void clear_pending_extents(void *_mds) +{ + struct cxl_memdev_state *mds = _mds; + struct cxl_extent *extent; + unsigned long index; + + xa_for_each(&mds->pending_extents, index, extent) + kfree(extent); + xa_destroy(&mds->pending_extents); +} + struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) { struct cxl_memdev_state *mds; + int rc; mds = devm_kzalloc(dev, sizeof(*mds), GFP_KERNEL); if (!mds) { @@ -1651,6 +1940,10 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) mds->pmem_perf.qos_class = CXL_QOS_CLASS_INVALID; for (int i = 0; i < CXL_MAX_DC_REGION; i++) mds->dc_perf[i].qos_class = CXL_QOS_CLASS_INVALID; + xa_init(&mds->pending_extents); + rc = devm_add_action_or_reset(dev, clear_pending_extents, mds); + if (rc) + return ERR_PTR(rc); return mds; } diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index a0c181cc33e4988e5c841d5b009d3d4aed5606c1..6ae51fc2bdae22fc25cc73773916714171512e92 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3036,6 +3036,7 @@ static void cxl_dax_region_release(struct device *dev) { struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev); + ida_destroy(&cxlr_dax->extent_ida); kfree(cxlr_dax); } @@ -3089,6 +3090,8 @@ static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr) dev = &cxlr_dax->dev; cxlr_dax->cxlr = cxlr; + cxlr->cxlr_dax = cxlr_dax; + ida_init(&cxlr_dax->extent_ida); device_initialize(dev); lockdep_set_class(&dev->mutex, &cxl_dax_region_key); device_set_pm_not_required(dev); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 46cc5ba502b2c46c68fd81c48b06f76f33282878..8a4c24ee7d216752a3351e29b9e5782a1a262f19 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include extern const struct nvdimm_security_ops *cxl_security_ops; @@ -169,11 +171,13 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw) #define CXLDEV_EVENT_STATUS_WARN BIT(1) #define CXLDEV_EVENT_STATUS_FAIL BIT(2) #define CXLDEV_EVENT_STATUS_FATAL BIT(3) +#define CXLDEV_EVENT_STATUS_DCD BIT(4) #define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO | \ CXLDEV_EVENT_STATUS_WARN | \ CXLDEV_EVENT_STATUS_FAIL | \ - CXLDEV_EVENT_STATUS_FATAL) + CXLDEV_EVENT_STATUS_FATAL | \ + CXLDEV_EVENT_STATUS_DCD) /* CXL rev 3.0 section 8.2.9.2.4; Table 8-52 */ #define CXLDEV_EVENT_INT_MODE_MASK GENMASK(1, 0) @@ -443,6 +447,18 @@ enum cxl_decoder_state { CXL_DECODER_STATE_AUTO, }; +/** + * struct cxled_extent - Extent within an endpoint decoder + * @cxled: Reference to the endpoint decoder + * @dpa_range: DPA range this extent covers within the decoder + * @tag: Tag from device for this extent + */ +struct cxled_extent { + struct cxl_endpoint_decoder *cxled; + struct range dpa_range; + u8 tag[CXL_EXTENT_TAG_LEN]; +}; + /** * struct cxl_endpoint_decoder - Endpoint / SPA to DPA decoder * @cxld: base cxl_decoder_object @@ -568,6 +584,7 @@ struct cxl_region_params { * @type: Endpoint decoder target type * @cxl_nvb: nvdimm bridge for coordinating @cxlr_pmem setup / shutdown * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge + * @cxlr_dax: (for DC regions) cached copy of CXL DAX bridge * @flags: Region state flags * @params: active + config params for the region * @coord: QoS access coordinates for the region @@ -581,6 +598,7 @@ struct cxl_region { enum cxl_decoder_type type; struct cxl_nvdimm_bridge *cxl_nvb; struct cxl_pmem_region *cxlr_pmem; + struct cxl_dax_region *cxlr_dax; unsigned long flags; struct cxl_region_params params; struct access_coordinate coord[ACCESS_COORDINATE_MAX]; @@ -621,12 +639,45 @@ struct cxl_pmem_region { struct cxl_pmem_region_mapping mapping[]; }; +/* See CXL 3.1 8.2.9.2.1.6 */ +enum dc_event { + DCD_ADD_CAPACITY, + DCD_RELEASE_CAPACITY, + DCD_FORCED_CAPACITY_RELEASE, + DCD_REGION_CONFIGURATION_UPDATED, +}; + struct cxl_dax_region { struct device dev; struct cxl_region *cxlr; struct range hpa_range; + struct ida extent_ida; }; +/** + * struct region_extent - CXL DAX region extent + * @dev: device representing this extent + * @cxlr_dax: back reference to parent region device + * @hpa_range: HPA range of this extent + * @tag: tag of the extent + * @decoder_extents: Endpoint decoder extents which make up this region extent + */ +struct region_extent { + struct device dev; + struct cxl_dax_region *cxlr_dax; + struct range hpa_range; + uuid_t tag; + struct xarray decoder_extents; +}; + +bool is_region_extent(struct device *dev); +static inline struct region_extent *to_region_extent(struct device *dev) +{ + if (!is_region_extent(dev)) + return NULL; + return container_of(dev, struct region_extent, dev); +} + /** * struct cxl_port - logical collection of upstream port devices and * downstream port devices to construct a CXL memory diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 863899b295b719b57638ee060e494e5cf2d639fd..73dee28bbd803a8f78686e833f8ef3492ca94e66 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "cxl.h" @@ -506,6 +507,7 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox) * @pmem_perf: performance data entry matched to PMEM partition * @nr_dc_region: number of DC regions implemented in the memory device * @dc_region: array containing info about the DC regions + * @pending_extents: array of extents pending during more bit processing * @event: event log driver state * @poison: poison driver state info * @security: security driver state info @@ -538,6 +540,7 @@ struct cxl_memdev_state { u8 nr_dc_region; struct cxl_dc_region_info dc_region[CXL_MAX_DC_REGION]; struct cxl_dpa_perf dc_perf[CXL_MAX_DC_REGION]; + struct xarray pending_extents; struct cxl_event_state event; struct cxl_poison_state poison; @@ -609,6 +612,21 @@ enum cxl_opcode { UUID_INIT(0x5e1819d9, 0x11a9, 0x400c, 0x81, 0x1f, 0xd6, 0x07, 0x19, \ 0x40, 0x3d, 0x86) +/* + * Add Dynamic Capacity Response + * CXL rev 3.1 section 8.2.9.9.9.3; Table 8-168 & Table 8-169 + */ +struct cxl_mbox_dc_response { + __le32 extent_list_size; + u8 flags; + u8 reserved[3]; + struct updated_extent_list { + __le64 dpa_start; + __le64 length; + u8 reserved[8]; + } __packed extent_list[]; +} __packed; + struct cxl_mbox_get_supported_logs { __le16 entries; u8 rsvd[6]; @@ -671,6 +689,14 @@ struct cxl_mbox_identify { UUID_INIT(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, 0x79, 0xba, 0xb1, \ 0x13, 0xb7, 0x74) +/* + * Dynamic Capacity Event Record + * CXL rev 3.1 section 8.2.9.2.1; Table 8-43 + */ +#define CXL_EVENT_DC_EVENT_UUID \ + UUID_INIT(0xca95afa7, 0xf183, 0x4018, 0x8c, 0x2f, 0x95, 0x26, 0x8e, \ + 0x10, 0x1a, 0x2a) + /* * Get Event Records output payload * CXL rev 3.0 section 8.2.9.2.2; Table 8-50 @@ -696,6 +722,7 @@ enum cxl_event_log_type { CXL_EVENT_TYPE_WARN, CXL_EVENT_TYPE_FAIL, CXL_EVENT_TYPE_FATAL, + CXL_EVENT_TYPE_DCD, CXL_EVENT_TYPE_MAX }; diff --git a/include/cxl/event.h b/include/cxl/event.h index 0bea1afbd747c4937b15703b581c569e7fa45ae4..eeda8059d81abef2fbf28cd3f3a6e516c9710229 100644 --- a/include/cxl/event.h +++ b/include/cxl/event.h @@ -96,11 +96,43 @@ struct cxl_event_mem_module { u8 reserved[0x3d]; } __packed; +/* + * CXL rev 3.1 section 8.2.9.2.1.6; Table 8-51 + */ +#define CXL_EXTENT_TAG_LEN 0x10 +struct cxl_extent { + __le64 start_dpa; + __le64 length; + u8 tag[CXL_EXTENT_TAG_LEN]; + __le16 shared_extn_seq; + u8 reserved[0x6]; +} __packed; + +/* + * Dynamic Capacity Event Record + * CXL rev 3.1 section 8.2.9.2.1.6; Table 8-50 + */ +#define CXL_DCD_EVENT_MORE BIT(0) +struct cxl_event_dcd { + struct cxl_event_record_hdr hdr; + u8 event_type; + u8 validity_flags; + __le16 host_id; + u8 region_index; + u8 flags; + u8 reserved1[0x2]; + struct cxl_extent extent; + u8 reserved2[0x18]; + __le32 num_avail_extents; + __le32 num_avail_tags; +} __packed; + union cxl_event { struct cxl_event_generic generic; struct cxl_event_gen_media gen_media; struct cxl_event_dram dram; struct cxl_event_mem_module mem_module; + struct cxl_event_dcd dcd; /* dram & gen_media event header */ struct cxl_event_media_hdr media_hdr; } __packed; diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index b1256fee3567fc7743812ee14bc46e09b7c8ba9b..bfa19587fd763ed552c2b9aa1a6e8981b6aa1c40 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -62,7 +62,8 @@ cxl_core-y += $(CXL_CORE_SRC)/hdm.o cxl_core-y += $(CXL_CORE_SRC)/pmu.o cxl_core-y += $(CXL_CORE_SRC)/cdat.o cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o -cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o +cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o \ + $(CXL_CORE_SRC)/extent.o cxl_core-y += config_check.o cxl_core-y += cxl_core_test.o cxl_core-y += cxl_core_exports.o From patchwork Thu Nov 7 20:58:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867151 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 33706224B46; Thu, 7 Nov 2024 20:59:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013159; cv=none; b=H5HaRmn63zZgxYozFpdrMOu+nUzu7lwH5Ex7iNFg+qTa646R6c9J4begXif/Dhqq1k2ARDXS2IDiOyKGPhDzgfHq1LvF4eLFOL0zJN1pu7sfAUMd6O6RV8ktNrh81w5u1sIfFdLFnNVo61ZZ9cZtcsJakcg4vNlJhpkOmEAWkfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013159; c=relaxed/simple; bh=/z57Di8+4MoIcNaFT/SVhi/tHc+RshShPSpFz6BZQZM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d47VzfgQ2J4daFdJe23+9oZu0PAhgUNcDygzBfkUqw2DQDaV9cyfhXPwcYAR3SdxCm5kWypRYPEMuZ2KhjisXdwSHRIzY/eyMHb3S9VJlsIC88t7uHAXvCZ8o+ub8Ty2iF0YUp3bERUSoi/q+PIc8p7rq6j+xU3E2ASbP85WSnk= 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=NaHu/nsS; arc=none smtp.client-ip=198.175.65.11 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="NaHu/nsS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013158; x=1762549158; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=/z57Di8+4MoIcNaFT/SVhi/tHc+RshShPSpFz6BZQZM=; b=NaHu/nsSou1mJaQn1Eq3YqEC3969HtHFvmR/S0Fsi5ocKI705emqWkaV TsvWhUdkOaUB0ZD48n2PkO0eX6t9MLV3PZUbdHLHonGunw2IqQvhLrpfH UV76bWXOMXqyBKoAOG/97DS2tNFYTkv2QfMrmFlkziPQarC8oq3pPtiGW i1XRfq1+Bpxs9X+hsv/ccUQ1IGDb6gEzOC9Ay/qp6/sPhGbN9YRKEC7E+ CNFsiRnZMtRF07vKRgKfrI5WbrhW/Kq+2yJNqoveCqwDi8J+mLJD5+BzI JHw3UJoQji74dBSdKWokAxKgWl+6gmp2xkt/JW/ukIKWtfxjLc6TwF+4+ g==; X-CSE-ConnectionGUID: q2/PwW5BRFakXBonml0Xpw== X-CSE-MsgGUID: lW3/OpNKReKRvwRfDDgQIA== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441087" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441087" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:17 -0800 X-CSE-ConnectionGUID: 6cH+0y/jQs+HMVx74GdEIA== X-CSE-MsgGUID: O8l+vN0TQrmPj8UnF87u9A== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746059" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:17 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:39 -0600 Subject: [PATCH v7 21/27] cxl/region/extent: Expose region extent information in sysfs Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-21-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=4991; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=jn/tPekUkdIM6oMRPpacsGan7cxQjZRBW1QHWy0/zyY=; b=7XzqkX9MMx20MqWaj09k9sQmmVImZuEKj3Fjklld1BaeII0NXX+HAFRNRhEpXbO5c7bHOJ08d 8wrDpeXgWKvBtu+3LSFnIyqbWAaoDaLcb0lpUldtT1HG6JMRP+kQdl8 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Extent information can be helpful to the user to coordinate memory usage with the external orchestrator and FM. Expose the details of region extents by creating the following sysfs entries. /sys/bus/cxl/devices/dax_regionX/extentX.Y /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset /sys/bus/cxl/devices/dax_regionX/extentX.Y/length /sys/bus/cxl/devices/dax_regionX/extentX.Y/tag Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Tested-by: Fan Ni Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- Documentation/ABI/testing/sysfs-bus-cxl | 33 +++++++++++++++++++ drivers/cxl/core/extent.c | 58 +++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index aeff248ea368cf49c9977fcaf43ab4def978e896..ee2ef4ea33e17cbc65e1252753f46f6d0dce1aee 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -632,3 +632,36 @@ Description: See Documentation/ABI/stable/sysfs-devices-node. access0 provides the number to the closest initiator and access1 provides the number to the closest CPU. + +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/offset +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) [For Dynamic Capacity regions only] Users can use the + extent information to create DAX devices on specific extents. + This is done by creating and destroying DAX devices in specific + sequences and looking at the mappings created. Extent offset + within the region. + +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/length +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) [For Dynamic Capacity regions only] Users can use the + extent information to create DAX devices on specific extents. + This is done by creating and destroying DAX devices in specific + sequences and looking at the mappings created. Extent length + within the region. + +What: /sys/bus/cxl/devices/dax_regionX/extentX.Y/tag +Date: December, 2024 +KernelVersion: v6.13 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) [For Dynamic Capacity regions only] Users can use the + extent information to create DAX devices on specific extents. + This is done by creating and destroying DAX devices in specific + sequences and looking at the mappings created. UUID extent + tag. diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c index bb12abe4792bcadd2442de3c21bf5ce4d48edf06..9f493aa8a5a26ca1dbaae48a396f67f0e644e1ce 100644 --- a/drivers/cxl/core/extent.c +++ b/drivers/cxl/core/extent.c @@ -6,6 +6,63 @@ #include "core.h" +static ssize_t offset_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct region_extent *region_extent = to_region_extent(dev); + + return sysfs_emit(buf, "%#llx\n", region_extent->hpa_range.start); +} +static DEVICE_ATTR_RO(offset); + +static ssize_t length_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct region_extent *region_extent = to_region_extent(dev); + u64 length = range_len(®ion_extent->hpa_range); + + return sysfs_emit(buf, "%#llx\n", length); +} +static DEVICE_ATTR_RO(length); + +static ssize_t tag_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct region_extent *region_extent = to_region_extent(dev); + + return sysfs_emit(buf, "%pUb\n", ®ion_extent->tag); +} +static DEVICE_ATTR_RO(tag); + +static struct attribute *region_extent_attrs[] = { + &dev_attr_offset.attr, + &dev_attr_length.attr, + &dev_attr_tag.attr, + NULL +}; + +static uuid_t empty_tag = { 0 }; + +static umode_t region_extent_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct region_extent *region_extent = to_region_extent(dev); + + if (a == &dev_attr_tag.attr && + uuid_equal(®ion_extent->tag, &empty_tag)) + return 0; + + return a->mode; +} + +static const struct attribute_group region_extent_attribute_group = { + .attrs = region_extent_attrs, + .is_visible = region_extent_visible, +}; + +__ATTRIBUTE_GROUPS(region_extent_attribute); + static void cxled_release_extent(struct cxl_endpoint_decoder *cxled, struct cxled_extent *ed_extent) { @@ -45,6 +102,7 @@ static void region_extent_release(struct device *dev) static const struct device_type region_extent_type = { .name = "extent", .release = region_extent_release, + .groups = region_extent_attribute_groups, }; bool is_region_extent(struct device *dev) From patchwork Thu Nov 7 20:58:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867153 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.11]) (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 EDC74224B5B; Thu, 7 Nov 2024 20:59:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013161; cv=none; b=RqlOwRIuVfpueaXau8ok4YW6nmpxH/gvtkxujfxuTPCrhQMGCA9N+MWXw6wok13K4Ebo9tHEelWsKEZSTT9CN0r06Fo7Ka5U7ROKsBgrlCfUQ+2qEDux44hM1nZQskRhfqbRcTySFBk31ItsA0Bgy1xy/n83qQBi0XMqg7pwxEA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013161; c=relaxed/simple; bh=bnEctiqnhcq8DDFcZJSlzCJp/l6KgaL6xctnE6VOTwM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uJHJ+nGk72ge3H9e5QWsWEQsikbENgTom4iyvF0qmAe5EVSck1vUWPkQJxlKGriNYJFfib473OqtB06V5eq75gLtauO0KzKqtjQDB3kwFYioVHZ+VX7OAqQe1CpSGBYlAlOOIIAzDzyIkBgnzbEF4qIjItSGcnSwojwwx0Nls7M= 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=ahiTMgNo; arc=none smtp.client-ip=198.175.65.11 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="ahiTMgNo" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013160; x=1762549160; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=bnEctiqnhcq8DDFcZJSlzCJp/l6KgaL6xctnE6VOTwM=; b=ahiTMgNopzrfyY1Id35pAJmTsk0z3WPO38ZTmfpcpV09kxW0Maqf+fzl Af42NB/cO7pT9aTV15fYfk0NFZ551wnMGyt8361UeEYH+T3lvWGwGoVaP 0RxCQ9EMh0sy436WozuPgAcqiWx3/m6+8lY2/9CwlkoAGwE0CZgIGSNE7 vrkXfo7RaWTTvig2sEhME4AcgOiaduPPo05S4tEMhtKe2OfH19imm2Ejm hDskz1Vhpu3GXdklH6RSt6MSEejOpsVESzjL2Lky4AmXLwLqTpPYVZGJx Twc3jAhiqFwRcHyxgxyU0ehXo5qjJQYNnduXbLdLSCDfrbJ6E1W9kaSxS g==; X-CSE-ConnectionGUID: T+4lxrsGT7a60RIKI+c2NQ== X-CSE-MsgGUID: 0ctZ0rpVSPChvIEvjNendQ== X-IronPort-AV: E=McAfee;i="6700,10204,11222"; a="41441095" X-IronPort-AV: E=Sophos;i="6.11,199,1725346800"; d="scan'208";a="41441095" Received: from orviesa001.jf.intel.com ([10.64.159.141]) by orvoesa103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:19 -0800 X-CSE-ConnectionGUID: Thwp+A2JRpat2sHFL1TQLw== X-CSE-MsgGUID: 32L0eczmS4StZQP3U3H9Pg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="122746065" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:19 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:40 -0600 Subject: [PATCH v7 22/27] dax/bus: Factor out dev dax resize logic Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-22-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=8814; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=bnEctiqnhcq8DDFcZJSlzCJp/l6KgaL6xctnE6VOTwM=; b=E72Bl7BFXrIJcoYqPPAZbBGPZUR/vtRwWaAJwv2hahEvXqvvFwAhaRR/g7kaoun3kKsF/w/nk wCIrJyghiP2BYeQt+kYTKQM09MbZ6bWdF01M6D1P/Oav6nmWnM/8Dd0 X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= Dynamic Capacity regions must limit dev dax resources to those areas which have extents backing real memory. Such DAX regions are dubbed 'sparse' regions. In order to manage where memory is available four alternatives were considered: 1) Create a single region resource child on region creation which reserves the entire region. Then as extents are added punch holes in this reservation. This requires new resource manipulation to punch the holes and still requires an additional iteration over the extent areas which may already have existing dev dax resources used. 2) Maintain an ordered xarray of extents which can be queried while processing the resize logic. The issue is that existing region->res children may artificially limit the allocation size sent to alloc_dev_dax_range(). IE the resource children can't be directly used in the resize logic to find where space in the region is. This also poses a problem of managing the available size in 2 places. 3) Maintain a separate resource tree with extents. This option is the same as 2) but with the different data structure. Most ideally there should be a unified representation of the resource tree not two places to look for space. 4) Create region resource children for each extent. Manage the dax dev resize logic in the same way as before but use a region child (extent) resource as the parents to find space within each extent. Option 4 can leverage the existing resize algorithm to find space within the extents. It manages the available space in a singular resource tree which is less complicated for finding space. In preparation for this change, factor out the dev_dax_resize logic. For static regions use dax_region->res as the parent to find space for the dax ranges. Future patches will use the same algorithm with individual extent resources as the parent. Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- drivers/dax/bus.c | 130 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 50 deletions(-) diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index d8cb5195a227c0f6194cb210510e006327e1b35b..c25942a3d1255cb5e5bf8d213e62933281ff3e4f 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -844,11 +844,9 @@ static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id) return 0; } -static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, - resource_size_t size) +static int alloc_dev_dax_range(struct resource *parent, struct dev_dax *dev_dax, + u64 start, resource_size_t size) { - struct dax_region *dax_region = dev_dax->region; - struct resource *res = &dax_region->res; struct device *dev = &dev_dax->dev; struct dev_dax_range *ranges; unsigned long pgoff = 0; @@ -866,14 +864,14 @@ static int alloc_dev_dax_range(struct dev_dax *dev_dax, u64 start, return 0; } - alloc = __request_region(res, start, size, dev_name(dev), 0); + alloc = __request_region(parent, start, size, dev_name(dev), 0); if (!alloc) return -ENOMEM; ranges = krealloc(dev_dax->ranges, sizeof(*ranges) * (dev_dax->nr_range + 1), GFP_KERNEL); if (!ranges) { - __release_region(res, alloc->start, resource_size(alloc)); + __release_region(parent, alloc->start, resource_size(alloc)); return -ENOMEM; } @@ -1026,50 +1024,45 @@ static bool adjust_ok(struct dev_dax *dev_dax, struct resource *res) return true; } -static ssize_t dev_dax_resize(struct dax_region *dax_region, - struct dev_dax *dev_dax, resource_size_t size) +/** + * dev_dax_resize_static - Expand the device into the unused portion of the + * region. This may involve adjusting the end of an existing resource, or + * allocating a new resource. + * + * @parent: parent resource to allocate this range in + * @dev_dax: DAX device to be expanded + * @to_alloc: amount of space to alloc; must be <= space available in @parent + * + * Return the amount of space allocated or -ERRNO on failure + */ +static ssize_t dev_dax_resize_static(struct resource *parent, + struct dev_dax *dev_dax, + resource_size_t to_alloc) { - resource_size_t avail = dax_region_avail_size(dax_region), to_alloc; - resource_size_t dev_size = dev_dax_size(dev_dax); - struct resource *region_res = &dax_region->res; - struct device *dev = &dev_dax->dev; struct resource *res, *first; - resource_size_t alloc = 0; int rc; - if (dev->driver) - return -EBUSY; - if (size == dev_size) - return 0; - if (size > dev_size && size - dev_size > avail) - return -ENOSPC; - if (size < dev_size) - return dev_dax_shrink(dev_dax, size); - - to_alloc = size - dev_size; - if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), - "resize of %pa misaligned\n", &to_alloc)) - return -ENXIO; - - /* - * Expand the device into the unused portion of the region. This - * may involve adjusting the end of an existing resource, or - * allocating a new resource. - */ -retry: - first = region_res->child; - if (!first) - return alloc_dev_dax_range(dev_dax, dax_region->res.start, to_alloc); + first = parent->child; + if (!first) { + rc = alloc_dev_dax_range(parent, dev_dax, + parent->start, to_alloc); + if (rc) + return rc; + return to_alloc; + } - rc = -ENOSPC; for (res = first; res; res = res->sibling) { struct resource *next = res->sibling; + resource_size_t alloc; /* space at the beginning of the region */ - if (res == first && res->start > dax_region->res.start) { - alloc = min(res->start - dax_region->res.start, to_alloc); - rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, alloc); - break; + if (res == first && res->start > parent->start) { + alloc = min(res->start - parent->start, to_alloc); + rc = alloc_dev_dax_range(parent, dev_dax, + parent->start, alloc); + if (rc) + return rc; + return alloc; } alloc = 0; @@ -1078,21 +1071,56 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region, alloc = min(next->start - (res->end + 1), to_alloc); /* space at the end of the region */ - if (!alloc && !next && res->end < region_res->end) - alloc = min(region_res->end - res->end, to_alloc); + if (!alloc && !next && res->end < parent->end) + alloc = min(parent->end - res->end, to_alloc); if (!alloc) continue; if (adjust_ok(dev_dax, res)) { rc = adjust_dev_dax_range(dev_dax, res, resource_size(res) + alloc); - break; + if (rc) + return rc; + return alloc; } - rc = alloc_dev_dax_range(dev_dax, res->end + 1, alloc); - break; + rc = alloc_dev_dax_range(parent, dev_dax, res->end + 1, alloc); + if (rc) + return rc; + return alloc; } - if (rc) - return rc; + + /* available was already calculated and should never be an issue */ + dev_WARN_ONCE(&dev_dax->dev, 1, "space not found?"); + return 0; +} + +static ssize_t dev_dax_resize(struct dax_region *dax_region, + struct dev_dax *dev_dax, resource_size_t size) +{ + resource_size_t avail = dax_region_avail_size(dax_region); + resource_size_t dev_size = dev_dax_size(dev_dax); + struct device *dev = &dev_dax->dev; + resource_size_t to_alloc; + resource_size_t alloc; + + if (dev->driver) + return -EBUSY; + if (size == dev_size) + return 0; + if (size > dev_size && size - dev_size > avail) + return -ENOSPC; + if (size < dev_size) + return dev_dax_shrink(dev_dax, size); + + to_alloc = size - dev_size; + if (dev_WARN_ONCE(dev, !alloc_is_aligned(dev_dax, to_alloc), + "resize of %pa misaligned\n", &to_alloc)) + return -ENXIO; + +retry: + alloc = dev_dax_resize_static(&dax_region->res, dev_dax, to_alloc); + if (alloc <= 0) + return alloc; to_alloc -= alloc; if (to_alloc) goto retry; @@ -1198,7 +1226,8 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, to_alloc = range_len(&r); if (alloc_is_aligned(dev_dax, to_alloc)) - rc = alloc_dev_dax_range(dev_dax, r.start, to_alloc); + rc = alloc_dev_dax_range(&dax_region->res, dev_dax, r.start, + to_alloc); up_write(&dax_dev_rwsem); up_write(&dax_region_rwsem); @@ -1466,7 +1495,8 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) device_initialize(dev); dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id); - rc = alloc_dev_dax_range(dev_dax, dax_region->res.start, data->size); + rc = alloc_dev_dax_range(&dax_region->res, dev_dax, dax_region->res.start, + data->size); if (rc) goto err_range; From patchwork Thu Nov 7 20:58:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867154 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) (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 41160226251; Thu, 7 Nov 2024 20:59:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013165; cv=none; b=UqftRQ+59yUZpA96nqZr48LHejwT6/BKJk42qiWirnLBIO96j0eNe60Bc4675Z+0RMIIsl7ViQnvn0513VPp5/IhYDG+Z6NQ3Fs6JsxAb3U9X07dJR+ogMSYd3QuPVOrUG9jcPsDCDoFNd5Fd3Ng0dKT9sMgPMy4F1qgZfzJJCk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013165; c=relaxed/simple; bh=YL8gieVgJUrtJTQckolrvXAf+U1Thtz2NC/7S2sQJco=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ESR6RQ+EN5btQbNDqL0qGCFGRNyKqgRd+qCBU1R6n2YdlRiIZ513t15gf66LUgGfCp34rVEHWHUVlLYc2AbPx+2OQDM9fEPZ+9gPFlvBbOfE66E7dDUr9NvFP+S5y/7ipFTPweA3H63zclnXGqir4J8EaNh9G/LRlG6HIdC3VgI= 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=e3/t4ENN; arc=none smtp.client-ip=192.198.163.13 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="e3/t4ENN" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013163; x=1762549163; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=YL8gieVgJUrtJTQckolrvXAf+U1Thtz2NC/7S2sQJco=; b=e3/t4ENNMcqB90+aYeiJuptGE1wpf6Y/X7ftaXSdtXyqZy3MhwtJ1JXM 0MOka9yY8MjEg5y8ZRYs7+zjNgEgDI1T3+/7vHhRh9UiwtpGBiTRmfSat rn7nYhV82ZNgOwJPMOOWQrAICi9h1UEmxqZ+pokcPSxakEfsOuvPAvd9o BYcj+02WQblLy/ha0Lf+0E8xVAbfLfpEwf6nrrzkBD4aaDhYa8pPeWgLU QOKV55kZdKbDxS/vMxA0xvPa96X0ir05triYgmXS5eDEcFu+o8vU6XL7U pMJR5YLd0bEw5k23dMj4ft+PQELne1qCYIG2DwHR3mTofBewnjKtcZA5V g==; X-CSE-ConnectionGUID: sXLv7tzcS2ac6vB/R/E55w== X-CSE-MsgGUID: HYn/8ForT4SIekVaZNujfQ== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="33727880" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="33727880" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:23 -0800 X-CSE-ConnectionGUID: 3FzPCOiWSM+HUsMAe3XYKw== X-CSE-MsgGUID: FUqFIWxATs+oTPxZDFrM4w== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="89875979" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:20 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:41 -0600 Subject: [PATCH v7 23/27] dax/region: Create resources on sparse DAX regions Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-23-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=30187; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=Uj79rOCwTA7iwFH1fj2KpTFYqkohy5bZvWtkj/ZlLN8=; b=2wNA2Yx7CByAO4e6sFSxXxLGxA1/3ZEZolUC2gpaHAySDj0sjbjTlFWfvD7J3i7fVXVvOJGWa G4eK+OyPVv5BT2CXQicsJfWKW+IXsUJgWyOuEQTwduONV7dygKcIStC X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh DAX regions which map dynamic capacity partitions require that memory be allowed to come and go. Recall sparse regions were created for this purpose. Now that extents can be realized within DAX regions the DAX region driver can start tracking sub-resource information. The tight relationship between DAX region operations and extent operations require memory changes to be controlled synchronously with the user of the region. Synchronize through the dax_region_rwsem and by having the region driver drive both the region device as well as the extent sub-devices. Recall requests to remove extents can happen at any time and that a host is not obligated to release the memory until it is not being used. If an extent is not used allow a release response. When extents are eligible for release. No mappings exist but data may reside in caches not yet written to the device. Call cxl_region_invalidate_memregion() to write back data to the device prior to signaling the release complete. Speculative writes after a release may dirty the cache such that a read from a newly surfaced extent may not come from the device. Call cxl_region_invalidate_memregion() prior to bringing a new extent online to ensure the cache is marked invalid. While these invalidate calls are inefficient they are the best we can do to ensure cache consistency without back invalidate. Furthermore this should occur infrequently with sufficiently large extents and work loads to not be too bad of an impact. The DAX layer has no need for the details of the CXL memory extent devices. Expose extents to the DAX layer as device children of the DAX region device. A single callback from the driver aids the DAX layer to determine if the child device is an extent. The DAX layer also registers a devres function to automatically clean up when the device is removed from the region. There is a race between extents being surfaced and the dax_cxl driver being loaded. The driver must therefore scan for any existing extents while still under the device lock. Respond to extent notifications. Manage the DAX region resource tree based on the extents lifetime. Return the status of remove notifications to lower layers such that it can manage the hardware appropriately. Reviewed-by: Jonathan Cameron Signed-off-by: Navneet Singh Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/core.h | 2 + drivers/cxl/core/extent.c | 85 ++++++++++++++-- drivers/cxl/core/region.c | 2 +- drivers/cxl/cxl.h | 6 ++ drivers/dax/bus.c | 246 +++++++++++++++++++++++++++++++++++++++++----- drivers/dax/bus.h | 3 +- drivers/dax/cxl.c | 61 +++++++++++- drivers/dax/dax-private.h | 40 ++++++++ drivers/dax/hmem/hmem.c | 2 +- drivers/dax/pmem.c | 2 +- include/linux/ioport.h | 3 + 11 files changed, 413 insertions(+), 39 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 0eccdd0b9261467fe762aa665776c87c5cb9ce24..c5951018f8ff590627676eeb7a430b6acbf516d8 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -21,6 +21,8 @@ cxled_to_mds(struct cxl_endpoint_decoder *cxled) return container_of(cxlds, struct cxl_memdev_state, cxlds); } +int cxl_region_invalidate_memregion(struct cxl_region *cxlr); + #ifdef CONFIG_CXL_REGION extern struct device_attribute dev_attr_create_pmem_region; extern struct device_attribute dev_attr_create_ram_region; diff --git a/drivers/cxl/core/extent.c b/drivers/cxl/core/extent.c index 9f493aa8a5a26ca1dbaae48a396f67f0e644e1ce..841cede20d508eaa907af62dc245149b8b37d5bd 100644 --- a/drivers/cxl/core/extent.c +++ b/drivers/cxl/core/extent.c @@ -117,6 +117,12 @@ static void region_extent_unregister(void *ext) dev_dbg(®ion_extent->dev, "DAX region rm extent HPA [range 0x%016llx-0x%016llx]\n", region_extent->hpa_range.start, region_extent->hpa_range.end); + /* + * Extent is not in use or an error has occur. No mappings + * exist at this point. Write and invalidate caches to ensure + * the device has all data prior to final release. + */ + cxl_region_invalidate_memregion(region_extent->cxlr_dax->cxlr); device_unregister(®ion_extent->dev); } @@ -270,20 +276,67 @@ static void calc_hpa_range(struct cxl_endpoint_decoder *cxled, hpa_range->end = hpa_range->start + range_len(dpa_range) - 1; } +static int cxlr_notify_extent(struct cxl_region *cxlr, enum dc_event event, + struct region_extent *region_extent) +{ + struct device *dev = &cxlr->cxlr_dax->dev; + struct cxl_notify_data notify_data; + struct cxl_driver *driver; + + dev_dbg(dev, "Trying notify: type %d HPA [range 0x%016llx-0x%016llx]\n", + event, + region_extent->hpa_range.start, region_extent->hpa_range.end); + + guard(device)(dev); + + /* + * The lack of a driver indicates a notification has failed. No user + * space coordination was possible. + */ + if (!dev->driver) + return 0; + driver = to_cxl_drv(dev->driver); + if (!driver->notify) + return 0; + + notify_data = (struct cxl_notify_data) { + .event = event, + .region_extent = region_extent, + }; + + dev_dbg(dev, "Notify: type %d HPA [range 0x%016llx-0x%016llx]\n", + event, + region_extent->hpa_range.start, region_extent->hpa_range.end); + return driver->notify(dev, ¬ify_data); +} + +struct rm_data { + struct cxl_region *cxlr; + struct range *range; +}; + static int cxlr_rm_extent(struct device *dev, void *data) { struct region_extent *region_extent = to_region_extent(dev); - struct range *region_hpa_range = data; + struct rm_data *rm_data = data; + int rc; if (!region_extent) return 0; /* - * Any extent which 'touches' the released range is removed. + * Any extent which 'touches' the released range is attempted to be + * removed. */ - if (range_overlaps(region_hpa_range, ®ion_extent->hpa_range)) { + if (range_overlaps(rm_data->range, ®ion_extent->hpa_range)) { + struct cxl_region *cxlr = rm_data->cxlr; + dev_dbg(dev, "Remove region extent HPA [range 0x%016llx-0x%016llx]\n", region_extent->hpa_range.start, region_extent->hpa_range.end); + rc = cxlr_notify_extent(cxlr, DCD_RELEASE_CAPACITY, region_extent); + if (rc == -EBUSY) + return 0; + region_rm_extent(region_extent); } return 0; @@ -328,8 +381,13 @@ int cxl_rm_extent(struct cxl_memdev_state *mds, struct cxl_extent *extent) calc_hpa_range(cxled, cxlr->cxlr_dax, &dpa_range, &hpa_range); + struct rm_data rm_data = { + .cxlr = cxlr, + .range = &hpa_range, + }; + /* Remove region extents which overlap */ - return device_for_each_child(&cxlr->cxlr_dax->dev, &hpa_range, + return device_for_each_child(&cxlr->cxlr_dax->dev, &rm_data, cxlr_rm_extent); } @@ -354,8 +412,23 @@ static int cxlr_add_extent(struct cxl_dax_region *cxlr_dax, return rc; } - /* device model handles freeing region_extent */ - return online_region_extent(region_extent); + /* Ensure caches are clean prior onlining */ + cxl_region_invalidate_memregion(cxlr_dax->cxlr); + + rc = online_region_extent(region_extent); + /* device model handled freeing region_extent */ + if (rc) + return rc; + + rc = cxlr_notify_extent(cxlr_dax->cxlr, DCD_ADD_CAPACITY, region_extent); + /* + * The region device was briefly live but DAX layer ensures it was not + * used + */ + if (rc) + region_rm_extent(region_extent); + + return rc; } /* Callers are expected to ensure cxled has been attached to a region */ diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 6ae51fc2bdae22fc25cc73773916714171512e92..7de9d7bd85a3d45567885874cc1d61cb10b816a5 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -223,7 +223,7 @@ static struct cxl_region_ref *cxl_rr_load(struct cxl_port *port, return xa_load(&port->regions, (unsigned long)cxlr); } -static int cxl_region_invalidate_memregion(struct cxl_region *cxlr) +int cxl_region_invalidate_memregion(struct cxl_region *cxlr) { if (!cpu_cache_has_invalidate_memregion()) { if (IS_ENABLED(CONFIG_CXL_REGION_INVALIDATION_TEST)) { diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 8a4c24ee7d216752a3351e29b9e5782a1a262f19..984554e9e8c255f9ceab18e9b0d57f0536b4e15f 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -918,10 +918,16 @@ bool is_cxl_region(struct device *dev); extern struct bus_type cxl_bus_type; +struct cxl_notify_data { + enum dc_event event; + struct region_extent *region_extent; +}; + struct cxl_driver { const char *name; int (*probe)(struct device *dev); void (*remove)(struct device *dev); + int (*notify)(struct device *dev, struct cxl_notify_data *notify_data); struct device_driver drv; int id; }; diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index c25942a3d1255cb5e5bf8d213e62933281ff3e4f..a54961fc393d71eda4a26f871597c6ffbb2023f8 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -183,6 +183,93 @@ static bool is_sparse(struct dax_region *dax_region) return (dax_region->res.flags & IORESOURCE_DAX_SPARSE_CAP) != 0; } +static void __dax_release_resource(struct dax_resource *dax_resource) +{ + struct dax_region *dax_region = dax_resource->region; + + lockdep_assert_held_write(&dax_region_rwsem); + dev_dbg(dax_region->dev, "Extent release resource %pr\n", + dax_resource->res); + if (dax_resource->res) + __release_region(&dax_region->res, dax_resource->res->start, + resource_size(dax_resource->res)); + dax_resource->res = NULL; +} + +static void dax_release_resource(void *res) +{ + struct dax_resource *dax_resource = res; + + guard(rwsem_write)(&dax_region_rwsem); + __dax_release_resource(dax_resource); + kfree(dax_resource); +} + +int dax_region_add_resource(struct dax_region *dax_region, + struct device *device, + resource_size_t start, resource_size_t length) +{ + struct resource *new_resource; + int rc; + + struct dax_resource *dax_resource __free(kfree) = + kzalloc(sizeof(*dax_resource), GFP_KERNEL); + if (!dax_resource) + return -ENOMEM; + + guard(rwsem_write)(&dax_region_rwsem); + + dev_dbg(dax_region->dev, "DAX region resource %pr\n", &dax_region->res); + new_resource = __request_region(&dax_region->res, start, length, "extent", 0); + if (!new_resource) { + dev_err(dax_region->dev, "Failed to add region s:%pa l:%pa\n", + &start, &length); + return -ENOSPC; + } + + dev_dbg(dax_region->dev, "add resource %pr\n", new_resource); + dax_resource->region = dax_region; + dax_resource->res = new_resource; + + /* + * open code devm_add_action_or_reset() to avoid recursive write lock + * of dax_region_rwsem in the error case. + */ + rc = devm_add_action(device, dax_release_resource, dax_resource); + if (rc) { + __dax_release_resource(dax_resource); + return rc; + } + + dev_set_drvdata(device, no_free_ptr(dax_resource)); + return 0; +} +EXPORT_SYMBOL_GPL(dax_region_add_resource); + +int dax_region_rm_resource(struct dax_region *dax_region, + struct device *dev) +{ + struct dax_resource *dax_resource; + + guard(rwsem_write)(&dax_region_rwsem); + + dax_resource = dev_get_drvdata(dev); + if (!dax_resource) + return 0; + + if (dax_resource->use_cnt) + return -EBUSY; + + /* + * release the resource under dax_region_rwsem to avoid races with + * users trying to use the extent + */ + __dax_release_resource(dax_resource); + dev_set_drvdata(dev, NULL); + return 0; +} +EXPORT_SYMBOL_GPL(dax_region_rm_resource); + bool static_dev_dax(struct dev_dax *dev_dax) { return is_static(dev_dax->region); @@ -296,19 +383,41 @@ static ssize_t region_align_show(struct device *dev, static struct device_attribute dev_attr_region_align = __ATTR(align, 0400, region_align_show, NULL); +resource_size_t +dax_avail_size(struct resource *dax_resource) +{ + resource_size_t rc; + struct resource *used_res; + + rc = resource_size(dax_resource); + for_each_child_resource(dax_resource, used_res) + rc -= resource_size(used_res); + return rc; +} +EXPORT_SYMBOL_GPL(dax_avail_size); + #define for_each_dax_region_resource(dax_region, res) \ for (res = (dax_region)->res.child; res; res = res->sibling) static unsigned long long dax_region_avail_size(struct dax_region *dax_region) { - resource_size_t size = resource_size(&dax_region->res); + resource_size_t size; struct resource *res; lockdep_assert_held(&dax_region_rwsem); - if (is_sparse(dax_region)) - return 0; + if (is_sparse(dax_region)) { + /* + * Children of a sparse region represent available space not + * used space. + */ + size = 0; + for_each_dax_region_resource(dax_region, res) + size += dax_avail_size(res); + return size; + } + size = resource_size(&dax_region->res); for_each_dax_region_resource(dax_region, res) size -= resource_size(res); return size; @@ -449,15 +558,26 @@ EXPORT_SYMBOL_GPL(kill_dev_dax); static void trim_dev_dax_range(struct dev_dax *dev_dax) { int i = dev_dax->nr_range - 1; - struct range *range = &dev_dax->ranges[i].range; + struct dev_dax_range *dev_range = &dev_dax->ranges[i]; + struct range *range = &dev_range->range; struct dax_region *dax_region = dev_dax->region; + struct resource *res = &dax_region->res; lockdep_assert_held_write(&dax_region_rwsem); dev_dbg(&dev_dax->dev, "delete range[%d]: %#llx:%#llx\n", i, (unsigned long long)range->start, (unsigned long long)range->end); - __release_region(&dax_region->res, range->start, range_len(range)); + if (dev_range->dax_resource) { + res = dev_range->dax_resource->res; + dev_dbg(&dev_dax->dev, "Trim sparse extent %pr\n", res); + } + + __release_region(res, range->start, range_len(range)); + + if (dev_range->dax_resource) + dev_range->dax_resource->use_cnt--; + if (--dev_dax->nr_range == 0) { kfree(dev_dax->ranges); dev_dax->ranges = NULL; @@ -640,7 +760,7 @@ static void dax_region_unregister(void *region) struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct range *range, int target_node, unsigned int align, - unsigned long flags) + unsigned long flags, struct dax_sparse_ops *sparse_ops) { struct dax_region *dax_region; @@ -658,12 +778,16 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, || !IS_ALIGNED(range_len(range), align)) return NULL; + if (!sparse_ops && (flags & IORESOURCE_DAX_SPARSE_CAP)) + return NULL; + dax_region = kzalloc(sizeof(*dax_region), GFP_KERNEL); if (!dax_region) return NULL; dev_set_drvdata(parent, dax_region); kref_init(&dax_region->kref); + dax_region->sparse_ops = sparse_ops; dax_region->id = region_id; dax_region->align = align; dax_region->dev = parent; @@ -845,7 +969,8 @@ static int devm_register_dax_mapping(struct dev_dax *dev_dax, int range_id) } static int alloc_dev_dax_range(struct resource *parent, struct dev_dax *dev_dax, - u64 start, resource_size_t size) + u64 start, resource_size_t size, + struct dax_resource *dax_resource) { struct device *dev = &dev_dax->dev; struct dev_dax_range *ranges; @@ -884,6 +1009,7 @@ static int alloc_dev_dax_range(struct resource *parent, struct dev_dax *dev_dax, .start = alloc->start, .end = alloc->end, }, + .dax_resource = dax_resource, }; dev_dbg(dev, "alloc range[%d]: %pa:%pa\n", dev_dax->nr_range - 1, @@ -966,7 +1092,8 @@ static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) int i; for (i = dev_dax->nr_range - 1; i >= 0; i--) { - struct range *range = &dev_dax->ranges[i].range; + struct dev_dax_range *dev_range = &dev_dax->ranges[i]; + struct range *range = &dev_range->range; struct dax_mapping *mapping = dev_dax->ranges[i].mapping; struct resource *adjust = NULL, *res; resource_size_t shrink; @@ -982,12 +1109,21 @@ static int dev_dax_shrink(struct dev_dax *dev_dax, resource_size_t size) continue; } - for_each_dax_region_resource(dax_region, res) - if (strcmp(res->name, dev_name(dev)) == 0 - && res->start == range->start) { - adjust = res; - break; - } + if (dev_range->dax_resource) { + for_each_child_resource(dev_range->dax_resource->res, res) + if (strcmp(res->name, dev_name(dev)) == 0 + && res->start == range->start) { + adjust = res; + break; + } + } else { + for_each_dax_region_resource(dax_region, res) + if (strcmp(res->name, dev_name(dev)) == 0 + && res->start == range->start) { + adjust = res; + break; + } + } if (dev_WARN_ONCE(dev, !adjust || i != dev_dax->nr_range - 1, "failed to find matching resource\n")) @@ -1025,19 +1161,21 @@ static bool adjust_ok(struct dev_dax *dev_dax, struct resource *res) } /** - * dev_dax_resize_static - Expand the device into the unused portion of the - * region. This may involve adjusting the end of an existing resource, or - * allocating a new resource. + * __dev_dax_resize - Expand the device into the unused portion of the region. + * This may involve adjusting the end of an existing resource, or allocating a + * new resource. * * @parent: parent resource to allocate this range in * @dev_dax: DAX device to be expanded * @to_alloc: amount of space to alloc; must be <= space available in @parent + * @dax_resource: if sparse; the parent resource * * Return the amount of space allocated or -ERRNO on failure */ -static ssize_t dev_dax_resize_static(struct resource *parent, - struct dev_dax *dev_dax, - resource_size_t to_alloc) +static ssize_t __dev_dax_resize(struct resource *parent, + struct dev_dax *dev_dax, + resource_size_t to_alloc, + struct dax_resource *dax_resource) { struct resource *res, *first; int rc; @@ -1045,7 +1183,8 @@ static ssize_t dev_dax_resize_static(struct resource *parent, first = parent->child; if (!first) { rc = alloc_dev_dax_range(parent, dev_dax, - parent->start, to_alloc); + parent->start, to_alloc, + dax_resource); if (rc) return rc; return to_alloc; @@ -1059,7 +1198,8 @@ static ssize_t dev_dax_resize_static(struct resource *parent, if (res == first && res->start > parent->start) { alloc = min(res->start - parent->start, to_alloc); rc = alloc_dev_dax_range(parent, dev_dax, - parent->start, alloc); + parent->start, alloc, + dax_resource); if (rc) return rc; return alloc; @@ -1083,7 +1223,8 @@ static ssize_t dev_dax_resize_static(struct resource *parent, return rc; return alloc; } - rc = alloc_dev_dax_range(parent, dev_dax, res->end + 1, alloc); + rc = alloc_dev_dax_range(parent, dev_dax, res->end + 1, alloc, + dax_resource); if (rc) return rc; return alloc; @@ -1094,6 +1235,51 @@ static ssize_t dev_dax_resize_static(struct resource *parent, return 0; } +static ssize_t dev_dax_resize_static(struct dax_region *dax_region, + struct dev_dax *dev_dax, + resource_size_t to_alloc) +{ + return __dev_dax_resize(&dax_region->res, dev_dax, to_alloc, NULL); +} + +static int find_free_extent(struct device *dev, void *data) +{ + struct dax_region *dax_region = data; + struct dax_resource *dax_resource; + + if (!dax_region->sparse_ops->is_extent(dev)) + return 0; + + dax_resource = dev_get_drvdata(dev); + if (!dax_resource || !dax_avail_size(dax_resource->res)) + return 0; + return 1; +} + +static ssize_t dev_dax_resize_sparse(struct dax_region *dax_region, + struct dev_dax *dev_dax, + resource_size_t to_alloc) +{ + struct dax_resource *dax_resource; + ssize_t alloc; + + struct device *extent_dev __free(put_device) = + device_find_child(dax_region->dev, dax_region, + find_free_extent); + if (!extent_dev) + return 0; + + dax_resource = dev_get_drvdata(extent_dev); + if (!dax_resource) + return 0; + + to_alloc = min(dax_avail_size(dax_resource->res), to_alloc); + alloc = __dev_dax_resize(dax_resource->res, dev_dax, to_alloc, dax_resource); + if (alloc > 0) + dax_resource->use_cnt++; + return alloc; +} + static ssize_t dev_dax_resize(struct dax_region *dax_region, struct dev_dax *dev_dax, resource_size_t size) { @@ -1118,7 +1304,10 @@ static ssize_t dev_dax_resize(struct dax_region *dax_region, return -ENXIO; retry: - alloc = dev_dax_resize_static(&dax_region->res, dev_dax, to_alloc); + if (is_sparse(dax_region)) + alloc = dev_dax_resize_sparse(dax_region, dev_dax, to_alloc); + else + alloc = dev_dax_resize_static(dax_region, dev_dax, to_alloc); if (alloc <= 0) return alloc; to_alloc -= alloc; @@ -1227,7 +1416,7 @@ static ssize_t mapping_store(struct device *dev, struct device_attribute *attr, to_alloc = range_len(&r); if (alloc_is_aligned(dev_dax, to_alloc)) rc = alloc_dev_dax_range(&dax_region->res, dev_dax, r.start, - to_alloc); + to_alloc, NULL); up_write(&dax_dev_rwsem); up_write(&dax_region_rwsem); @@ -1466,6 +1655,11 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) struct device *dev; int rc; + if (is_sparse(dax_region) && data->size) { + dev_err(parent, "Sparse DAX region devices must be created initially with 0 size"); + return ERR_PTR(-EINVAL); + } + dev_dax = kzalloc(sizeof(*dev_dax), GFP_KERNEL); if (!dev_dax) return ERR_PTR(-ENOMEM); @@ -1496,7 +1690,7 @@ static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data) dev_set_name(dev, "dax%d.%d", dax_region->id, dev_dax->id); rc = alloc_dev_dax_range(&dax_region->res, dev_dax, dax_region->res.start, - data->size); + data->size, NULL); if (rc) goto err_range; diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index 783bfeef42cc6c4d74f24e0a69dac5598eaf1664..ae5029ea6047c5c640a504e1bb3d815a75498a3a 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -9,6 +9,7 @@ struct dev_dax; struct resource; struct dax_device; struct dax_region; +struct dax_sparse_ops; /* dax bus specific ioresource flags */ #define IORESOURCE_DAX_STATIC BIT(0) @@ -17,7 +18,7 @@ struct dax_region; struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct range *range, int target_node, unsigned int align, - unsigned long flags); + unsigned long flags, struct dax_sparse_ops *sparse_ops); struct dev_dax_data { struct dax_region *dax_region; diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c index 367e86b1c22a2a0af7070677a7b7fc54bc2b0214..bd2034c3090110525fdc0520d55a9a25fa4739f8 100644 --- a/drivers/dax/cxl.c +++ b/drivers/dax/cxl.c @@ -5,6 +5,57 @@ #include "../cxl/cxl.h" #include "bus.h" +#include "dax-private.h" + +static int __cxl_dax_add_resource(struct dax_region *dax_region, + struct region_extent *region_extent) +{ + struct device *dev = ®ion_extent->dev; + resource_size_t start, length; + + start = dax_region->res.start + region_extent->hpa_range.start; + length = range_len(®ion_extent->hpa_range); + return dax_region_add_resource(dax_region, dev, start, length); +} + +static int cxl_dax_add_resource(struct device *dev, void *data) +{ + struct dax_region *dax_region = data; + struct region_extent *region_extent; + + region_extent = to_region_extent(dev); + if (!region_extent) + return 0; + + dev_dbg(dax_region->dev, "Adding resource HPA %pra\n", + ®ion_extent->hpa_range); + + return __cxl_dax_add_resource(dax_region, region_extent); +} + +static int cxl_dax_region_notify(struct device *dev, + struct cxl_notify_data *notify_data) +{ + struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev); + struct dax_region *dax_region = dev_get_drvdata(dev); + struct region_extent *region_extent = notify_data->region_extent; + + switch (notify_data->event) { + case DCD_ADD_CAPACITY: + return __cxl_dax_add_resource(dax_region, region_extent); + case DCD_RELEASE_CAPACITY: + return dax_region_rm_resource(dax_region, ®ion_extent->dev); + case DCD_FORCED_CAPACITY_RELEASE: + default: + dev_err(&cxlr_dax->dev, "Unknown DC event %d\n", + notify_data->event); + return -ENXIO; + } +} + +struct dax_sparse_ops sparse_ops = { + .is_extent = is_region_extent, +}; static int cxl_dax_region_probe(struct device *dev) { @@ -24,15 +75,18 @@ static int cxl_dax_region_probe(struct device *dev) flags |= IORESOURCE_DAX_SPARSE_CAP; dax_region = alloc_dax_region(dev, cxlr->id, &cxlr_dax->hpa_range, nid, - PMD_SIZE, flags); + PMD_SIZE, flags, &sparse_ops); if (!dax_region) return -ENOMEM; - if (cxlr->mode == CXL_REGION_DC) + if (cxlr->mode == CXL_REGION_DC) { + device_for_each_child(&cxlr_dax->dev, dax_region, + cxl_dax_add_resource); /* Add empty seed dax device */ dev_size = 0; - else + } else { dev_size = range_len(&cxlr_dax->hpa_range); + } data = (struct dev_dax_data) { .dax_region = dax_region, @@ -47,6 +101,7 @@ static int cxl_dax_region_probe(struct device *dev) static struct cxl_driver cxl_dax_region_driver = { .name = "cxl_dax_region", .probe = cxl_dax_region_probe, + .notify = cxl_dax_region_notify, .id = CXL_DEVICE_DAX_REGION, .drv = { .suppress_bind_attrs = true, diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 0867115aeef2e1b2d4c88b5c38b6648a404b1060..39fb587561f802b813c1763293820307520d6adf 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -16,6 +16,14 @@ struct inode *dax_inode(struct dax_device *dax_dev); int dax_bus_init(void); void dax_bus_exit(void); +/** + * struct dax_sparse_ops - Operations for sparse regions + * @is_extent: return if the device is an extent + */ +struct dax_sparse_ops { + bool (*is_extent)(struct device *dev); +}; + /** * struct dax_region - mapping infrastructure for dax devices * @id: kernel-wide unique region for a memory range @@ -27,6 +35,7 @@ void dax_bus_exit(void); * @res: resource tree to track instance allocations * @seed: allow userspace to find the first unbound seed device * @youngest: allow userspace to find the most recently created device + * @sparse_ops: operations required for sparse regions */ struct dax_region { int id; @@ -38,6 +47,7 @@ struct dax_region { struct resource res; struct device *seed; struct device *youngest; + struct dax_sparse_ops *sparse_ops; }; /** @@ -57,11 +67,13 @@ struct dax_mapping { * @pgoff: page offset * @range: resource-span * @mapping: reference to the dax_mapping for this range + * @dax_resource: if not NULL; dax sparse resource containing this range */ struct dev_dax_range { unsigned long pgoff; struct range range; struct dax_mapping *mapping; + struct dax_resource *dax_resource; }; /** @@ -100,6 +112,34 @@ struct dev_dax { */ void run_dax(struct dax_device *dax_dev); +/** + * struct dax_resource - For sparse regions; an active resource + * @region: dax_region this resources is in + * @res: resource + * @use_cnt: count the number of uses of this resource + * + * Changes to the dax_region and the dax_resources within it are protected by + * dax_region_rwsem + * + * dax_resource's are not intended to be used outside the dax layer. + */ +struct dax_resource { + struct dax_region *region; + struct resource *res; + unsigned int use_cnt; +}; + +/* + * Similar to run_dax() dax_region_{add,rm}_resource() and dax_avail_size() are + * exported but are not intended to be generic operations outside the dax + * subsystem. They are only generic between the dax layer and the dax drivers. + */ +int dax_region_add_resource(struct dax_region *dax_region, struct device *dev, + resource_size_t start, resource_size_t length); +int dax_region_rm_resource(struct dax_region *dax_region, + struct device *dev); +resource_size_t dax_avail_size(struct resource *dax_resource); + static inline struct dev_dax *to_dev_dax(struct device *dev) { return container_of(dev, struct dev_dax, dev); diff --git a/drivers/dax/hmem/hmem.c b/drivers/dax/hmem/hmem.c index 5e7c53f18491622408adeab9d354ea869dbc71de..0eea65052874edc983690e1fe071ae2f7bc6aa7e 100644 --- a/drivers/dax/hmem/hmem.c +++ b/drivers/dax/hmem/hmem.c @@ -28,7 +28,7 @@ static int dax_hmem_probe(struct platform_device *pdev) mri = dev->platform_data; dax_region = alloc_dax_region(dev, pdev->id, &mri->range, - mri->target_node, PMD_SIZE, flags); + mri->target_node, PMD_SIZE, flags, NULL); if (!dax_region) return -ENOMEM; diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index c8ebf4e281f2405034065014ecdb830afda66906..f927e855f240007276612674448c155d89494746 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -54,7 +54,7 @@ static struct dev_dax *__dax_pmem_probe(struct device *dev) range.start += offset; dax_region = alloc_dax_region(dev, region_id, &range, nd_region->target_node, le32_to_cpu(pfn_sb->align), - IORESOURCE_DAX_STATIC); + IORESOURCE_DAX_STATIC, NULL); if (!dax_region) return ERR_PTR(-ENOMEM); diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 6e9fb667a1c5a5d5f7b415ac1e21ac082569f256..6a328772591143e72221cec6b0ed0772f88b6641 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -27,6 +27,9 @@ struct resource { struct resource *parent, *sibling, *child; }; +#define for_each_child_resource(parent, res) \ + for (res = (parent)->child; res; res = res->sibling) + /* * IO resources have these defined flags. * From patchwork Thu Nov 7 20:58:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867155 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) (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 D72BA226268; Thu, 7 Nov 2024 20:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013167; cv=none; b=WE6K2PX2/ilDMgS59CM8vI7Usu0E1a0JHctawCVLYgbyhPf6xAAIJMNQNh6vANqpRKm8OEVF4T+oJrXV8TBvhAJlOIHRNkJYBX3tvd1vJLJHQeLh9aRQX3rU5y+EZFlI/2vzii2N7m54Bq5atI6zIO7v5hKQ+Vp1YjwViiJx2mo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013167; c=relaxed/simple; bh=uUM8W6dGW1EQOn8n05onnanB1G6mRCZKn0zEd+Lh9I8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ts290dpe2qcoxMaPYOqbkv30R67keS0X3G3uDwtC16qWw1LaDeXwcczQM+iqIXF3WnVML+vefYjVso8WE6ZRkPFph5PmIknfelmhZ8Xg8ptUmCiewQYc5b2tolklCGMJ47dLDl5qa9Jo3pEA1HFwOp8uY8jAHwg18nx3nSezQEA= 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=LFCZoQDe; arc=none smtp.client-ip=192.198.163.13 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="LFCZoQDe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013166; x=1762549166; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=uUM8W6dGW1EQOn8n05onnanB1G6mRCZKn0zEd+Lh9I8=; b=LFCZoQDeO6K/oOG3RV2dI4/gaN656xDqURGCJjjGPqGIRPUdv5UvUhkz O6ZD9m5H7MHKsiwXz5f37PqR7uN2YVzcJY0t6siiYlXOl0cxbP8rbF3WJ lxNO114Wf/nR+wAyIFXuSsqFvcLrifx6XyoDzHL1Ygz1zBRQKkyyhZwF4 zesWsPOiGybEAu7CMP8Juq2KQZxP3flXHNEXiPnP5xesG8r8In/BNpZqF 72x7nDwtUnVnvpED6gjH6GGaExlxNRWUQLqn23OVy5RCZiTkk6S6DgsCS zhi9xUGfF4JGlqXc8CgaAuON1bSJmiXQYNrqbnCa2VkQA8WnyRSNdoMVq w==; X-CSE-ConnectionGUID: UvdjPlZrQiutU/lIYDI6kg== X-CSE-MsgGUID: 6f8Is8m0SP+YkF494xmMOQ== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="33727890" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="33727890" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:25 -0800 X-CSE-ConnectionGUID: QNiHfl0CSwqHb0gQiXF/Pw== X-CSE-MsgGUID: igtRZJDYRJW0iTFtZ9iGsA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="89876010" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:23 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:42 -0600 Subject: [PATCH v7 24/27] cxl/region: Read existing extents on region creation Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-24-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=8645; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=CbTELjbaPfBPqnwtKdfhL6NaUCWUkGIAn8BdcMxxAlQ=; b=CB87Vt01yCH0uFAmNMGhzU12sDZoNiGTBICpbmKmXRS2IEo9Xfq/LwPJWsr2NhdGYaGzquqhd QJKzjPpCzfrBXMxe910TGHfMP0GThG7ijHssBHQpZ98ZHuMfIkSbaTp X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh Dynamic capacity device extents may be left in an accepted state on a device due to an unexpected host crash. In this case it is expected that the creation of a new region on top of a DC partition can read those extents and surface them for continued use. Once all endpoint decoders are part of a region and the region is being realized, a read of the 'devices extent list' can reveal these previously accepted extents. CXL r3.1 specifies the mailbox call Get Dynamic Capacity Extent List for this purpose. The call returns all the extents for all dynamic capacity partitions. If the fabric manager is adding extents to any DCD partition, the extent list for the recovered region may change. In this case the query must retry. Upon retry the query could encounter extents which were accepted on a previous list query. Adding such extents is ignored without error because they are entirely within a previous accepted extent. Instead warn on this case to allow for differentiating bad devices from this normal condition. Latch any errors to be bubbled up to ensure notification to the user even if individual errors are rate limited or otherwise ignored. The scan for existing extents races with the dax_cxl driver. This is synchronized through the region device lock. Extents which are found after the driver has loaded will surface through the normal notification path while extents seen prior to the driver are read during driver load. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Fan Ni Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/core.h | 1 + drivers/cxl/core/mbox.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/region.c | 25 +++++++++++ drivers/cxl/cxlmem.h | 21 +++++++++ 4 files changed, 155 insertions(+) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index c5951018f8ff590627676eeb7a430b6acbf516d8..feb00bbe98c9b59d2c7fceb3ad5fed3885b59753 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -21,6 +21,7 @@ cxled_to_mds(struct cxl_endpoint_decoder *cxled) return container_of(cxlds, struct cxl_memdev_state, cxlds); } +int cxl_process_extent_list(struct cxl_endpoint_decoder *cxled); int cxl_region_invalidate_memregion(struct cxl_region *cxlr); #ifdef CONFIG_CXL_REGION diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 61d406d19bf777a3921dbb3cc1213d341d8dea4c..e0030166ea185f8ad9194f597906d61497897654 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1699,6 +1699,114 @@ int cxl_dev_dynamic_capacity_identify(struct cxl_memdev_state *mds) } EXPORT_SYMBOL_NS_GPL(cxl_dev_dynamic_capacity_identify, CXL); +/* Return -EAGAIN if the extent list changes while reading */ +static int __cxl_process_extent_list(struct cxl_endpoint_decoder *cxled) +{ + u32 current_index, total_read, total_expected, initial_gen_num; + struct cxl_memdev_state *mds = cxled_to_mds(cxled); + struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox; + struct device *dev = mds->cxlds.dev; + struct cxl_mbox_cmd mbox_cmd; + u32 max_extent_count; + int latched_rc = 0; + bool first = true; + + struct cxl_mbox_get_extent_out *extents __free(kvfree) = + kvmalloc(cxl_mbox->payload_size, GFP_KERNEL); + if (!extents) + return -ENOMEM; + + total_read = 0; + current_index = 0; + total_expected = 0; + max_extent_count = (cxl_mbox->payload_size - sizeof(*extents)) / + sizeof(struct cxl_extent); + do { + struct cxl_mbox_get_extent_in get_extent; + u32 nr_returned, current_total, current_gen_num; + int rc; + + get_extent = (struct cxl_mbox_get_extent_in) { + .extent_cnt = max(max_extent_count, + total_expected - current_index), + .start_extent_index = cpu_to_le32(current_index), + }; + + mbox_cmd = (struct cxl_mbox_cmd) { + .opcode = CXL_MBOX_OP_GET_DC_EXTENT_LIST, + .payload_in = &get_extent, + .size_in = sizeof(get_extent), + .size_out = cxl_mbox->payload_size, + .payload_out = extents, + .min_out = 1, + }; + + rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd); + if (rc < 0) + return rc; + + /* Save initial data */ + if (first) { + total_expected = le32_to_cpu(extents->total_extent_count); + initial_gen_num = le32_to_cpu(extents->generation_num); + first = false; + } + + nr_returned = le32_to_cpu(extents->returned_extent_count); + total_read += nr_returned; + current_total = le32_to_cpu(extents->total_extent_count); + current_gen_num = le32_to_cpu(extents->generation_num); + + dev_dbg(dev, "Got extent list %d-%d of %d generation Num:%d\n", + current_index, total_read - 1, current_total, current_gen_num); + + if (current_gen_num != initial_gen_num || total_expected != current_total) { + dev_warn(dev, "Extent list change detected; gen %u != %u : cnt %u != %u\n", + current_gen_num, initial_gen_num, + total_expected, current_total); + return -EAGAIN; + } + + for (int i = 0; i < nr_returned ; i++) { + struct cxl_extent *extent = &extents->extent[i]; + + dev_dbg(dev, "Processing extent %d/%d\n", + current_index + i, total_expected); + + rc = validate_add_extent(mds, extent); + if (rc) + latched_rc = rc; + } + + current_index += nr_returned; + } while (total_expected > total_read); + + return latched_rc; +} + +/** + * cxl_process_extent_list() - Read existing extents + * @cxled: Endpoint decoder which is part of a region + * + * Issue the Get Dynamic Capacity Extent List command to the device + * and add existing extents if found. + * + * A retry of 10 is somewhat arbitrary, however, extent changes should be + * relatively rare while bringing up a region. So 10 should be plenty. + */ +#define CXL_READ_EXTENT_LIST_RETRY 10 +int cxl_process_extent_list(struct cxl_endpoint_decoder *cxled) +{ + int retry = CXL_READ_EXTENT_LIST_RETRY; + int rc; + + do { + rc = __cxl_process_extent_list(cxled); + } while (rc == -EAGAIN && retry--); + + return rc; +} + static int add_dpa_res(struct device *dev, struct resource *parent, struct resource *res, resource_size_t start, resource_size_t size, const char *type) diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 7de9d7bd85a3d45567885874cc1d61cb10b816a5..b160f8a95cd7d4415c6252b3a9f36b06490ddf45 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3190,6 +3190,26 @@ static int devm_cxl_add_pmem_region(struct cxl_region *cxlr) return rc; } +static int cxlr_add_existing_extents(struct cxl_region *cxlr) +{ + struct cxl_region_params *p = &cxlr->params; + int i, latched_rc = 0; + + for (i = 0; i < p->nr_targets; i++) { + struct device *dev = &p->targets[i]->cxld.dev; + int rc; + + rc = cxl_process_extent_list(p->targets[i]); + if (rc) { + dev_err(dev, "Existing extent processing failed %d\n", + rc); + latched_rc = rc; + } + } + + return latched_rc; +} + static void cxlr_dax_unregister(void *_cxlr_dax) { struct cxl_dax_region *cxlr_dax = _cxlr_dax; @@ -3224,6 +3244,11 @@ static int devm_cxl_add_dax_region(struct cxl_region *cxlr) dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent), dev_name(dev)); + if (cxlr->mode == CXL_REGION_DC) + if (cxlr_add_existing_extents(cxlr)) + dev_err(&cxlr->dev, "Existing extent processing failed %d\n", + rc); + return devm_add_action_or_reset(&cxlr->dev, cxlr_dax_unregister, cxlr_dax); err: diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index 73dee28bbd803a8f78686e833f8ef3492ca94e66..e7b9bd5bb4a96b0cdeb4bcf9c3b7ca1499d1cddd 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -627,6 +627,27 @@ struct cxl_mbox_dc_response { } __packed extent_list[]; } __packed; +/* + * Get Dynamic Capacity Extent List; Input Payload + * CXL rev 3.1 section 8.2.9.9.9.2; Table 8-166 + */ +struct cxl_mbox_get_extent_in { + __le32 extent_cnt; + __le32 start_extent_index; +} __packed; + +/* + * Get Dynamic Capacity Extent List; Output Payload + * CXL rev 3.1 section 8.2.9.9.9.2; Table 8-167 + */ +struct cxl_mbox_get_extent_out { + __le32 returned_extent_count; + __le32 total_extent_count; + __le32 generation_num; + u8 rsvd[4]; + struct cxl_extent extent[]; +} __packed; + struct cxl_mbox_get_supported_logs { __le16 entries; u8 rsvd[6]; From patchwork Thu Nov 7 20:58:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867156 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) (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 E88A4226B6B; Thu, 7 Nov 2024 20:59:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013170; cv=none; b=c1uBJgNF5axNrZZV2rP0YcyDOxwRYtwEyuCTA5BRCxvnz9Sl7y5Fu+Kqc4GgalFROOTq9zxwou8DXhvQ6yfhDgGqSqepGoqoM8CcvWEopil8+wnq9m5vRvZsjG7vydips0L6pwDzwnW7LiC81hUn1tO4gaOwJTvy0hzvOEf0sZw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013170; c=relaxed/simple; bh=nTzBiYM0ZGEhiXRDqoR0889r/eTviFwdO8Ts8yXZInw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XUuZyl5QMGJyQL6DJNGh2hjK2krCv388WGxrt7FxC/ovqQQMyLefCo5S3n3z+oOrNwdLAHONBddPFpGWsgvsx2NxaYNVYiGYgj2/KsZNUYLTuFUgvBEXO7KdjjjLZCpXg7r4Ad1t0Y5S9phqruGWjNrIHF4ekbcU/zCniS9osnA= 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=WxFJ1v5F; arc=none smtp.client-ip=192.198.163.13 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="WxFJ1v5F" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013169; x=1762549169; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=nTzBiYM0ZGEhiXRDqoR0889r/eTviFwdO8Ts8yXZInw=; b=WxFJ1v5FXb747dBXt21DVxlWOxQ+aFcYdg8rOZJy1O2a9Pg6Ard2JFlz ITRHwQkG7WwLxUX4oD1e3Z7JLkAVpoku8YKdhADDfE9zFYUsISeLZwmZL 5AIJagkpN17reEOCfCSgb5/DuZiPcThQ4lblTlfb2ENe1i3sThhlYjHTF mX5lA9ubnGhKViyA0VyMWRTgAqEHIhzo+NmwWVD91Txc794bqGMrAmOAH RXob1yCGbsdhXHrttgioVXTt9l5+zzHPxOEjwgmLaaI5exeMu9puzkOa0 PGnvMr/D0MpiPcWy4nN11TsQM05mPrxAa8cCsjNC4LNKvaxz+/1w2zI6n Q==; X-CSE-ConnectionGUID: zZar2UZpR8CUxpzmL5RfQA== X-CSE-MsgGUID: ZjmfleS6RdqXWfAmG469bw== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="33727898" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="33727898" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:28 -0800 X-CSE-ConnectionGUID: yRYjAStDQZKbpdB/esBiCQ== X-CSE-MsgGUID: kLHVG+gJRWmfP03JbbHSFg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="89876029" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:26 -0800 From: ira.weiny@intel.com Date: Thu, 07 Nov 2024 14:58:43 -0600 Subject: [PATCH v7 25/27] cxl/mem: Trace Dynamic capacity Event Record Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-25-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=3591; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=vaAw0rjPm835wNAX6U7iwIQUmgsQgCIKUhARp6y953I=; b=NROw/mk2M8pm3PbtWDijQxm9w4vsjzu7l1WEsIQdGivOL/prKxB7y3JylDRE9+K3YGw6k5RFQ zQmdcQNpfDHB+3LNrEWCZ6zs7xQsBKkUDzj6XSzoUyPwhOMTLEVCDsK X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= From: Navneet Singh CXL rev 3.1 section 8.2.9.2.1 adds the Dynamic Capacity Event Records. User space can use trace events for debugging of DC capacity changes. Add DC trace points to the trace log. Signed-off-by: Navneet Singh Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Reviewed-by: Fan Ni Co-developed-by: Ira Weiny Signed-off-by: Ira Weiny --- drivers/cxl/core/mbox.c | 4 +++ drivers/cxl/core/trace.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index e0030166ea185f8ad9194f597906d61497897654..8261ce126a4bd23e5f717a9035f75668753ec276 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -995,6 +995,10 @@ static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, ev_type = CXL_CPER_EVENT_DRAM; else if (uuid_equal(uuid, &CXL_EVENT_MEM_MODULE_UUID)) ev_type = CXL_CPER_EVENT_MEM_MODULE; + else if (uuid_equal(uuid, &CXL_EVENT_DC_EVENT_UUID)) { + trace_cxl_dynamic_capacity(cxlmd, type, &record->event.dcd); + return; + } cxl_event_trace_record(cxlmd, type, ev_type, uuid, &record->event); } diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index 8672b42ee4d1b376063b09d29922fcce83a70168..d4526f06cf2a2d0a4b4bc5f9e00238aa43a16e35 100644 --- a/drivers/cxl/core/trace.h +++ b/drivers/cxl/core/trace.h @@ -731,6 +731,71 @@ TRACE_EVENT(cxl_poison, ) ); +/* + * Dynamic Capacity Event Record - DER + * + * CXL rev 3.1 section 8.2.9.2.1.6 Table 8-50 + */ + +#define CXL_DC_ADD_CAPACITY 0x00 +#define CXL_DC_REL_CAPACITY 0x01 +#define CXL_DC_FORCED_REL_CAPACITY 0x02 +#define CXL_DC_REG_CONF_UPDATED 0x03 +#define show_dc_evt_type(type) __print_symbolic(type, \ + { CXL_DC_ADD_CAPACITY, "Add capacity"}, \ + { CXL_DC_REL_CAPACITY, "Release capacity"}, \ + { CXL_DC_FORCED_REL_CAPACITY, "Forced capacity release"}, \ + { CXL_DC_REG_CONF_UPDATED, "Region Configuration Updated" } \ +) + +TRACE_EVENT(cxl_dynamic_capacity, + + TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log, + struct cxl_event_dcd *rec), + + TP_ARGS(cxlmd, log, rec), + + TP_STRUCT__entry( + CXL_EVT_TP_entry + + /* Dynamic capacity Event */ + __field(u8, event_type) + __field(u16, hostid) + __field(u8, region_id) + __field(u64, dpa_start) + __field(u64, length) + __array(u8, tag, CXL_EXTENT_TAG_LEN) + __field(u16, sh_extent_seq) + ), + + TP_fast_assign( + CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); + + /* Dynamic_capacity Event */ + __entry->event_type = rec->event_type; + + /* DCD event record data */ + __entry->hostid = le16_to_cpu(rec->host_id); + __entry->region_id = rec->region_index; + __entry->dpa_start = le64_to_cpu(rec->extent.start_dpa); + __entry->length = le64_to_cpu(rec->extent.length); + memcpy(__entry->tag, &rec->extent.tag, CXL_EXTENT_TAG_LEN); + __entry->sh_extent_seq = le16_to_cpu(rec->extent.shared_extn_seq); + ), + + CXL_EVT_TP_printk("event_type='%s' host_id='%d' region_id='%d' " \ + "starting_dpa=%llx length=%llx tag=%pU " \ + "shared_extent_sequence=%d", + show_dc_evt_type(__entry->event_type), + __entry->hostid, + __entry->region_id, + __entry->dpa_start, + __entry->length, + __entry->tag, + __entry->sh_extent_seq + ) +); + #endif /* _CXL_EVENTS_H */ #define TRACE_INCLUDE_FILE trace From patchwork Thu Nov 7 20:58:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867157 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) (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 DA994226B83; Thu, 7 Nov 2024 20:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013172; cv=none; b=US/XVdOFJvlzX7qzVDANpNlppNjv8aoMx0uP2w3ZgbndeMv2P25NWqZJi/3NIBbkIetRjQFW5E9RK7PxE9uV6yUQ9YWWwuGT88UuKUBFjaPAPyZrYM0El7BuKFcWaXCp7EE0ZtxEH0OUbJLSRdW2eu2qyR/1sQ0WLCZxa9sqEWI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013172; c=relaxed/simple; bh=2Vycd2tVNexSZra4jq61u55rDAGYrO2GPqDdjO2Y8Vg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lqS2Ms4kTw9OlASQA5rbO9XaX0DjeeiyIgmJBdrVTrxm2rInIxTaJspvHi/Huzv0VeE4H0/WpYGXa14kT6XN3CMjd7wQwrsiJCwpSMWDTXpbE7SUcLYXJA4nvo034MIuHnZjH7m+2gokZnKQkUQolEpBf+csWNlYTkfIDhuwUXk= 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=f+mtc+pc; arc=none smtp.client-ip=192.198.163.13 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="f+mtc+pc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013171; x=1762549171; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=2Vycd2tVNexSZra4jq61u55rDAGYrO2GPqDdjO2Y8Vg=; b=f+mtc+pcRrlMFsIZrY3UVTH6ZIt2bAdw/s9Mc3ZBSeDOOI29WFObK9sY 69gDNd/P2mf+wwniAlbQU6/mnpSXBAN5S0eqtQM2HKfaDfzWLbi+mKplp xJGiP0mlewlaMJf1VXKP993hPQ8ec0u3DbGeM3/+IKX4D0ZPWPZFVzfuZ XJCuW71J1Y0rSS/OZ3SnQcfVvhn0mrb4lIxwWEA32r8multkjVPL+DdSU /Tp2wckv+6+aCQ5Rv9mm+WRoWXjJMVTqWYvLX/jtD29joV55f4CUQyAt4 F7q5nJdp4YV3eqAsC5CiaMTs4hcRlpp22b65FC5M/2tk6wxndO4zLfB3P w==; X-CSE-ConnectionGUID: IykrqhjTSKSBTYkP8uqpgQ== X-CSE-MsgGUID: HJ97MLLNRTSXQGJXMQPhAQ== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="33727912" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="33727912" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:31 -0800 X-CSE-ConnectionGUID: o0DSPvzlTWSQ6wzG8YbmVA== X-CSE-MsgGUID: 2u7uuGCLT1WD2ST76R5ClQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="89876049" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:29 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:44 -0600 Subject: [PATCH v7 26/27] tools/testing/cxl: Make event logs dynamic Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-26-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=15571; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=2Vycd2tVNexSZra4jq61u55rDAGYrO2GPqDdjO2Y8Vg=; b=iLlW8BmCuZ3QWDRjKAYEeA9X8TeQIHUOoZz4oSlYo5STpMQBkGCkSwx4mSQOQZABHkdI/U6lp 9RmITRe6eOnCJeybgSsEOzmVFVP8+r6X34e+fYBWCAiC92Gt+KIKJbQ X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= The event logs test was created as static arrays as an easy way to mock events. Dynamic Capacity Device (DCD) test support requires events be generated dynamically when extents are created or destroyed. The current event log test has specific checks for the number of events seen including log overflow. Modify mock event logs to be dynamically allocated. Adjust array size and mock event entry data to match the output expected by the existing event test. Use the static event data to create the dynamic events in the new logs without inventing complex event injection for the previous tests. Simplify log processing by using the event log array index as the handle. Add a lock to manage concurrency required when user space is allowed to control DCD extents Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- tools/testing/cxl/test/mem.c | 268 ++++++++++++++++++++++++++----------------- 1 file changed, 162 insertions(+), 106 deletions(-) diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index ad5c4c18c5c643aff7180a686c1990a136069f6d..611cd9677cd0a63214322189efb4ef9fb3a1ceb6 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -126,18 +126,26 @@ static struct { #define PASS_TRY_LIMIT 3 -#define CXL_TEST_EVENT_CNT_MAX 15 +#define CXL_TEST_EVENT_CNT_MAX 16 +/* 1 extra slot to accommodate that handles can't be 0 */ +#define CXL_TEST_EVENT_ARRAY_SIZE (CXL_TEST_EVENT_CNT_MAX + 1) /* Set a number of events to return at a time for simulation. */ #define CXL_TEST_EVENT_RET_MAX 4 +/* + * @last_handle: last handle (index) to have an entry stored + * @current_handle: current handle (index) to be returned to the user on get_event + * @nr_overflow: number of events added past the log size + * @lock: protect these state variables + * @events: array of pending events to be returned. + */ struct mock_event_log { - u16 clear_idx; - u16 cur_idx; - u16 nr_events; + u16 last_handle; + u16 current_handle; u16 nr_overflow; - u16 overflow_reset; - struct cxl_event_record_raw *events[CXL_TEST_EVENT_CNT_MAX]; + rwlock_t lock; + struct cxl_event_record_raw *events[CXL_TEST_EVENT_ARRAY_SIZE]; }; struct mock_event_store { @@ -172,56 +180,65 @@ static struct mock_event_log *event_find_log(struct device *dev, int log_type) return &mdata->mes.mock_logs[log_type]; } -static struct cxl_event_record_raw *event_get_current(struct mock_event_log *log) -{ - return log->events[log->cur_idx]; -} - -static void event_reset_log(struct mock_event_log *log) -{ - log->cur_idx = 0; - log->clear_idx = 0; - log->nr_overflow = log->overflow_reset; -} - /* Handle can never be 0 use 1 based indexing for handle */ -static u16 event_get_clear_handle(struct mock_event_log *log) +static u16 event_inc_handle(u16 handle) { - return log->clear_idx + 1; + handle = (handle + 1) % CXL_TEST_EVENT_ARRAY_SIZE; + if (handle == 0) + handle = 1; + return handle; } -/* Handle can never be 0 use 1 based indexing for handle */ -static __le16 event_get_cur_event_handle(struct mock_event_log *log) -{ - u16 cur_handle = log->cur_idx + 1; - - return cpu_to_le16(cur_handle); -} - -static bool event_log_empty(struct mock_event_log *log) -{ - return log->cur_idx == log->nr_events; -} - -static void mes_add_event(struct mock_event_store *mes, +/* Add the event or free it on overflow */ +static void mes_add_event(struct cxl_mockmem_data *mdata, enum cxl_event_log_type log_type, struct cxl_event_record_raw *event) { + struct device *dev = mdata->mds->cxlds.dev; struct mock_event_log *log; if (WARN_ON(log_type >= CXL_EVENT_TYPE_MAX)) return; - log = &mes->mock_logs[log_type]; + log = &mdata->mes.mock_logs[log_type]; + + guard(write_lock)(&log->lock); - if ((log->nr_events + 1) > CXL_TEST_EVENT_CNT_MAX) { + dev_dbg(dev, "Add log %d cur %d last %d\n", + log_type, log->current_handle, log->last_handle); + + /* Check next buffer */ + if (event_inc_handle(log->last_handle) == log->current_handle) { log->nr_overflow++; - log->overflow_reset = log->nr_overflow; + dev_dbg(dev, "Overflowing log %d nr %d\n", + log_type, log->nr_overflow); + devm_kfree(dev, event); return; } - log->events[log->nr_events] = event; - log->nr_events++; + dev_dbg(dev, "Log %d; handle %u\n", log_type, log->last_handle); + event->event.generic.hdr.handle = cpu_to_le16(log->last_handle); + log->events[log->last_handle] = event; + log->last_handle = event_inc_handle(log->last_handle); +} + +static void mes_del_event(struct device *dev, + struct mock_event_log *log, + u16 handle) +{ + struct cxl_event_record_raw *record; + + lockdep_assert(lockdep_is_held(&log->lock)); + + dev_dbg(dev, "Clearing event %u; record %u\n", + handle, log->current_handle); + record = log->events[handle]; + if (!record) + dev_err(dev, "Mock event index %u empty?\n", handle); + + log->events[handle] = NULL; + log->current_handle = event_inc_handle(log->current_handle); + devm_kfree(dev, record); } /* @@ -234,7 +251,7 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd) { struct cxl_get_event_payload *pl; struct mock_event_log *log; - u16 nr_overflow; + u16 handle; u8 log_type; int i; @@ -255,29 +272,38 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd) memset(cmd->payload_out, 0, struct_size(pl, records, 0)); log = event_find_log(dev, log_type); - if (!log || event_log_empty(log)) + if (!log) return 0; pl = cmd->payload_out; - for (i = 0; i < ret_limit && !event_log_empty(log); i++) { - memcpy(&pl->records[i], event_get_current(log), - sizeof(pl->records[i])); - pl->records[i].event.generic.hdr.handle = - event_get_cur_event_handle(log); - log->cur_idx++; + guard(read_lock)(&log->lock); + + handle = log->current_handle; + dev_dbg(dev, "Get log %d handle %u last %u\n", + log_type, handle, log->last_handle); + for (i = 0; i < ret_limit && handle != log->last_handle; + i++, handle = event_inc_handle(handle)) { + struct cxl_event_record_raw *cur; + + cur = log->events[handle]; + dev_dbg(dev, "Sending event log %d handle %d idx %u\n", + log_type, le16_to_cpu(cur->event.generic.hdr.handle), + handle); + memcpy(&pl->records[i], cur, sizeof(pl->records[i])); + pl->records[i].event.generic.hdr.handle = cpu_to_le16(handle); } cmd->size_out = struct_size(pl, records, i); pl->record_count = cpu_to_le16(i); - if (!event_log_empty(log)) + if (handle != log->last_handle) pl->flags |= CXL_GET_EVENT_FLAG_MORE_RECORDS; if (log->nr_overflow) { u64 ns; pl->flags |= CXL_GET_EVENT_FLAG_OVERFLOW; - pl->overflow_err_count = cpu_to_le16(nr_overflow); + pl->overflow_err_count = cpu_to_le16(log->nr_overflow); ns = ktime_get_real_ns(); ns -= 5000000000; /* 5s ago */ pl->first_overflow_timestamp = cpu_to_le64(ns); @@ -292,8 +318,8 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd) static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd) { struct cxl_mbox_clear_event_payload *pl = cmd->payload_in; - struct mock_event_log *log; u8 log_type = pl->event_log; + struct mock_event_log *log; u16 handle; int nr; @@ -304,23 +330,20 @@ static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd) if (!log) return 0; /* No mock data in this log */ - /* - * This check is technically not invalid per the specification AFAICS. - * (The host could 'guess' handles and clear them in order). - * However, this is not good behavior for the host so test it. - */ - if (log->clear_idx + pl->nr_recs > log->cur_idx) { - dev_err(dev, - "Attempting to clear more events than returned!\n"); - return -EINVAL; - } + guard(write_lock)(&log->lock); /* Check handle order prior to clearing events */ - for (nr = 0, handle = event_get_clear_handle(log); - nr < pl->nr_recs; - nr++, handle++) { + handle = log->current_handle; + for (nr = 0; nr < pl->nr_recs && handle != log->last_handle; + nr++, handle = event_inc_handle(handle)) { + + dev_dbg(dev, "Checking clear of %d handle %u plhandle %u\n", + log_type, handle, + le16_to_cpu(pl->handles[nr])); + if (handle != le16_to_cpu(pl->handles[nr])) { - dev_err(dev, "Clearing events out of order\n"); + dev_err(dev, "Clearing events out of order %u %u\n", + handle, le16_to_cpu(pl->handles[nr])); return -EINVAL; } } @@ -329,25 +352,12 @@ static int mock_clear_event(struct device *dev, struct cxl_mbox_cmd *cmd) log->nr_overflow = 0; /* Clear events */ - log->clear_idx += pl->nr_recs; - return 0; -} - -static void cxl_mock_event_trigger(struct device *dev) -{ - struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); - struct mock_event_store *mes = &mdata->mes; - int i; + for (nr = 0; nr < pl->nr_recs; nr++) + mes_del_event(dev, log, le16_to_cpu(pl->handles[nr])); + dev_dbg(dev, "Delete log %d cur %d last %d\n", + log_type, log->current_handle, log->last_handle); - for (i = CXL_EVENT_TYPE_INFO; i < CXL_EVENT_TYPE_MAX; i++) { - struct mock_event_log *log; - - log = event_find_log(dev, i); - if (log) - event_reset_log(log); - } - - cxl_mem_get_event_records(mdata->mds, mes->ev_status); + return 0; } struct cxl_event_record_raw maint_needed = { @@ -476,8 +486,27 @@ static int mock_set_timestamp(struct cxl_dev_state *cxlds, return 0; } -static void cxl_mock_add_event_logs(struct mock_event_store *mes) +/* Create a dynamically allocated event out of a statically defined event. */ +static void add_event_from_static(struct cxl_mockmem_data *mdata, + enum cxl_event_log_type log_type, + struct cxl_event_record_raw *raw) +{ + struct device *dev = mdata->mds->cxlds.dev; + struct cxl_event_record_raw *rec; + + rec = devm_kmemdup(dev, raw, sizeof(*rec), GFP_KERNEL); + if (!rec) { + dev_err(dev, "Failed to alloc event for log\n"); + return; + } + mes_add_event(mdata, log_type, rec); +} + +static void cxl_mock_add_event_logs(struct cxl_mockmem_data *mdata) { + struct mock_event_store *mes = &mdata->mes; + struct device *dev = mdata->mds->cxlds.dev; + put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK, &gen_media.rec.media_hdr.validity_flags); @@ -485,43 +514,60 @@ static void cxl_mock_add_event_logs(struct mock_event_store *mes) CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN, &dram.rec.media_hdr.validity_flags); - mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed); - mes_add_event(mes, CXL_EVENT_TYPE_INFO, + dev_dbg(dev, "Generating fake event logs %d\n", + CXL_EVENT_TYPE_INFO); + add_event_from_static(mdata, CXL_EVENT_TYPE_INFO, &maint_needed); + add_event_from_static(mdata, CXL_EVENT_TYPE_INFO, (struct cxl_event_record_raw *)&gen_media); - mes_add_event(mes, CXL_EVENT_TYPE_INFO, + add_event_from_static(mdata, CXL_EVENT_TYPE_INFO, (struct cxl_event_record_raw *)&mem_module); mes->ev_status |= CXLDEV_EVENT_STATUS_INFO; - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &maint_needed); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, + dev_dbg(dev, "Generating fake event logs %d\n", + CXL_EVENT_TYPE_FAIL); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &maint_needed); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, + (struct cxl_event_record_raw *)&mem_module); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, (struct cxl_event_record_raw *)&dram); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, (struct cxl_event_record_raw *)&gen_media); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, (struct cxl_event_record_raw *)&mem_module); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, (struct cxl_event_record_raw *)&dram); /* Overflow this log */ - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FAIL, &hardware_replace); mes->ev_status |= CXLDEV_EVENT_STATUS_FAIL; - mes_add_event(mes, CXL_EVENT_TYPE_FATAL, &hardware_replace); - mes_add_event(mes, CXL_EVENT_TYPE_FATAL, + dev_dbg(dev, "Generating fake event logs %d\n", + CXL_EVENT_TYPE_FATAL); + add_event_from_static(mdata, CXL_EVENT_TYPE_FATAL, &hardware_replace); + add_event_from_static(mdata, CXL_EVENT_TYPE_FATAL, (struct cxl_event_record_raw *)&dram); mes->ev_status |= CXLDEV_EVENT_STATUS_FATAL; } +static void cxl_mock_event_trigger(struct device *dev) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct mock_event_store *mes = &mdata->mes; + + cxl_mock_add_event_logs(mdata); + cxl_mem_get_event_records(mdata->mds, mes->ev_status); +} + static int mock_gsl(struct cxl_mbox_cmd *cmd) { if (cmd->size_out < sizeof(mock_gsl_payload)) @@ -1469,6 +1515,14 @@ static int cxl_mock_mailbox_create(struct cxl_dev_state *cxlds) return 0; } +static void init_event_log(struct mock_event_log *log) +{ + rwlock_init(&log->lock); + /* Handle can never be 0 use 1 based indexing for handle */ + log->current_handle = 1; + log->last_handle = 1; +} + static int cxl_mock_mem_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1541,7 +1595,9 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) if (rc) return rc; - cxl_mock_add_event_logs(&mdata->mes); + for (int i = 0; i < CXL_EVENT_TYPE_MAX; i++) + init_event_log(&mdata->mes.mock_logs[i]); + cxl_mock_add_event_logs(mdata); cxlmd = devm_cxl_add_memdev(&pdev->dev, cxlds); if (IS_ERR(cxlmd)) From patchwork Thu Nov 7 20:58:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ira Weiny X-Patchwork-Id: 13867158 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.13]) (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 640A622736C; Thu, 7 Nov 2024 20:59:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.13 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013175; cv=none; b=bQD0pfiCGWx2KuKSmIuLfQLl5t8qjxC0aE/EMn7S4iVva+covSgKvKYnXvfSQzb+zGkSFa77J2m09jt7pWWydURWkKIG6mONxGKjlSw5itFvi2OqUY+edMv9NWgoAuQVPnBrbbSOcZsS/vfAAq7tk745lZ+Cy+v945Op0BlQ7F8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731013175; c=relaxed/simple; bh=k991MK4r78KnjLGKTIuGJXPFi1B64lQS84XmSbrEd5c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JsrMWSZUPojNJZpayKATF8DHb33ayRHKG65yq+WKZGTl6+4eN+ip1xyhvDFa1wL5b+ljizScI4V3MjAwoQS5zfcaGQGxP1kLIAJefgwsyATcjn9fLXL8JL4KiafZvxei9MkaE1y9JvrCsbmx9JqhT8UB5Bapotu/rregEujwYiU= 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=NRrC+N3B; arc=none smtp.client-ip=192.198.163.13 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="NRrC+N3B" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1731013174; x=1762549174; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=k991MK4r78KnjLGKTIuGJXPFi1B64lQS84XmSbrEd5c=; b=NRrC+N3BjABEVz+mTOxWkK/z3TLTbwy0PVqnksn623V3NCkr1TSFMb4B vJUGh4GTYSR4iZScbKX55ZGTQDRlxMKGRra96N4ZPOOIkId1Rl7XbRl1p YmxnD/3WOnmJaCHNqiybXcbY0VwcepiG4JwooDxahPbuOboRrlFk8kHr+ G9+nnU+QdtvtaVzRCOjTtOpMnOzshJdDuYfjgQFQTV9yi+u9TboN1iQ0c lkROTgVkbICwLWRqqq86Dx2BGj3eqRLX2QrK5Bx0ERspzpQ6JcFzKITLy u8iGVB3dEKZrDhl4ZjVr1LKTmN52DdEcteh9nJDgBEOyKe/+Om35iLhIx Q==; X-CSE-ConnectionGUID: lwjftcRtRh6Q2iNQ6uecwA== X-CSE-MsgGUID: vBemgSffRQKEfX1mZ68Qvg== X-IronPort-AV: E=McAfee;i="6700,10204,11249"; a="33727922" X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="33727922" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by fmvoesa107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:33 -0800 X-CSE-ConnectionGUID: AJryEevjSWaWMpRe6XVFBg== X-CSE-MsgGUID: IowlDCGNSluQkV+wBhfR1g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.12,136,1728975600"; d="scan'208";a="89876064" Received: from aschofie-mobl2.amr.corp.intel.com (HELO localhost) ([10.125.110.195]) by fmviesa004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Nov 2024 12:59:31 -0800 From: Ira Weiny Date: Thu, 07 Nov 2024 14:58:45 -0600 Subject: [PATCH v7 27/27] tools/testing/cxl: Add DC Regions to mock mem data Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241107-dcd-type2-upstream-v7-27-56a84e66bc36@intel.com> References: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> In-Reply-To: <20241107-dcd-type2-upstream-v7-0-56a84e66bc36@intel.com> To: Dave Jiang , Fan Ni , Jonathan Cameron , Navneet Singh , Jonathan Corbet , Andrew Morton Cc: Dan Williams , Davidlohr Bueso , Alison Schofield , Vishal Verma , Ira Weiny , linux-cxl@vger.kernel.org, linux-doc@vger.kernel.org, nvdimm@lists.linux.dev, linux-kernel@vger.kernel.org X-Mailer: b4 0.15-dev-2a633 X-Developer-Signature: v=1; a=ed25519-sha256; t=1731013104; l=24637; i=ira.weiny@intel.com; s=20221211; h=from:subject:message-id; bh=k991MK4r78KnjLGKTIuGJXPFi1B64lQS84XmSbrEd5c=; b=WrvDeZoa9J5kAzW0D62YooSuSZeE4FfIRm0T0gBXCxOXM2P5SnesvOsRATZXOUGBlf91UbtZQ qexrlWcZNBRDwtQfkrJkThGiosNMvkhKCrrlD2A9i1W1+pDW9RITV4N X-Developer-Key: i=ira.weiny@intel.com; a=ed25519; pk=noldbkG+Wp1qXRrrkfY1QJpDf7QsOEthbOT7vm0PqsE= cxl_test provides a good way to ensure quick smoke and regression testing. The complexity of Dynamic Capacity (DC) extent processing as well as the complexity of the new sparse DAX regions can mostly be tested through cxl_test. This includes management of sparse regions and DAX devices on those regions; the management of extent device lifetimes; and the processing of DCD events. The only missing functionality from this test is actual interrupt processing. Mock memory devices can easily mock DC information and manage fake extent data. Define mock_dc_region information within the mock memory data. Add sysfs entries on the mock device to inject and delete extents. The inject format is ::: The delete format is : Directly call the event irq callback to simulate irqs to process the test extents. Add DC mailbox commands to the CEL and implement those commands. Reviewed-by: Jonathan Cameron Reviewed-by: Dave Jiang Signed-off-by: Ira Weiny --- Changes: [iweiny: expand test realism to allow the host to reject extents properly] --- tools/testing/cxl/test/mem.c | 751 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 751 insertions(+) diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index 611cd9677cd0a63214322189efb4ef9fb3a1ceb6..3d00e07e147c90f1ea2bc1fdad2fb4c04e3aaa1d 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -20,6 +20,7 @@ #define FW_SLOTS 3 #define DEV_SIZE SZ_2G #define EFFECT(x) (1U << x) +#define BASE_DYNAMIC_CAP_DPA DEV_SIZE #define MOCK_INJECT_DEV_MAX 8 #define MOCK_INJECT_TEST_MAX 128 @@ -97,6 +98,22 @@ static struct cxl_cel_entry mock_cel[] = { EFFECT(SECURITY_CHANGE_IMMEDIATE) | EFFECT(BACKGROUND_OP)), }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_DC_CONFIG), + .effect = CXL_CMD_EFFECT_NONE, + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_DC_EXTENT_LIST), + .effect = CXL_CMD_EFFECT_NONE, + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_ADD_DC_RESPONSE), + .effect = cpu_to_le16(EFFECT(CONF_CHANGE_IMMEDIATE)), + }, + { + .opcode = cpu_to_le16(CXL_MBOX_OP_RELEASE_DC), + .effect = cpu_to_le16(EFFECT(CONF_CHANGE_IMMEDIATE)), + }, }; /* See CXL 2.0 Table 181 Get Health Info Output Payload */ @@ -153,6 +170,7 @@ struct mock_event_store { u32 ev_status; }; +#define NUM_MOCK_DC_REGIONS 2 struct cxl_mockmem_data { void *lsa; void *fw; @@ -169,6 +187,18 @@ struct cxl_mockmem_data { u8 event_buf[SZ_4K]; u64 timestamp; unsigned long sanitize_timeout; + struct cxl_dc_region_config dc_regions[NUM_MOCK_DC_REGIONS]; + u32 dc_ext_generation; + struct mutex ext_lock; + /* + * Extents are in 1 of 3 states + * FM (sysfs added but not sent to the host yet) + * sent (sent to the host but not accepted) + * accepted (by the host) + */ + struct xarray dc_fm_extents; + struct xarray dc_sent_extents; + struct xarray dc_accepted_exts; }; static struct mock_event_log *event_find_log(struct device *dev, int log_type) @@ -568,6 +598,251 @@ static void cxl_mock_event_trigger(struct device *dev) cxl_mem_get_event_records(mdata->mds, mes->ev_status); } +struct cxl_extent_data { + u64 dpa_start; + u64 length; + u8 tag[CXL_EXTENT_TAG_LEN]; + bool shared; +}; + +static int __devm_add_extent(struct device *dev, struct xarray *array, + u64 start, u64 length, const char *tag, + bool shared) +{ + struct cxl_extent_data *extent; + + extent = devm_kzalloc(dev, sizeof(*extent), GFP_KERNEL); + if (!extent) + return -ENOMEM; + + extent->dpa_start = start; + extent->length = length; + memcpy(extent->tag, tag, min(sizeof(extent->tag), strlen(tag))); + extent->shared = shared; + + if (xa_insert(array, start, extent, GFP_KERNEL)) { + devm_kfree(dev, extent); + dev_err(dev, "Failed xarry insert %#llx\n", start); + return -EINVAL; + } + + return 0; +} + +static int devm_add_fm_extent(struct device *dev, u64 start, u64 length, + const char *tag, bool shared) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + + guard(mutex)(&mdata->ext_lock); + return __devm_add_extent(dev, &mdata->dc_fm_extents, start, length, + tag, shared); +} + +/* It is known that ext and the new range are not equal */ +static struct cxl_extent_data * +split_ext(struct device *dev, struct xarray *array, + struct cxl_extent_data *ext, u64 start, u64 length) +{ + u64 new_start, new_length; + + if (ext->dpa_start == start) { + new_start = start + length; + new_length = (ext->dpa_start + ext->length) - new_start; + + if (__devm_add_extent(dev, array, new_start, new_length, + ext->tag, false)) + return NULL; + + ext = xa_erase(array, ext->dpa_start); + if (__devm_add_extent(dev, array, start, length, ext->tag, + false)) + return NULL; + + return xa_load(array, start); + } + + /* ext->dpa_start != start */ + + if (__devm_add_extent(dev, array, start, length, ext->tag, false)) + return NULL; + + new_start = ext->dpa_start; + new_length = start - ext->dpa_start; + + ext = xa_erase(array, ext->dpa_start); + if (__devm_add_extent(dev, array, new_start, new_length, ext->tag, + false)) + return NULL; + + return xa_load(array, start); +} + +/* + * Do not handle extents which are not inside a single extent sent to + * the host. + */ +static struct cxl_extent_data * +find_create_ext(struct device *dev, struct xarray *array, u64 start, u64 length) +{ + struct cxl_extent_data *ext; + unsigned long index; + + xa_for_each(array, index, ext) { + u64 end = start + length; + + /* start < [ext) <= start */ + if (start < ext->dpa_start || + (ext->dpa_start + ext->length) <= start) + continue; + + if (end <= ext->dpa_start || + (ext->dpa_start + ext->length) < end) { + dev_err(dev, "Invalid range %#llx-%#llx\n", start, + end); + return NULL; + } + + break; + } + + if (!ext) + return NULL; + + if (start == ext->dpa_start && length == ext->length) + return ext; + + return split_ext(dev, array, ext, start, length); +} + +static int dc_accept_extent(struct device *dev, u64 start, u64 length) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_extent_data *ext; + + dev_dbg(dev, "Host accepting extent %#llx\n", start); + mdata->dc_ext_generation++; + + lockdep_assert_held(&mdata->ext_lock); + ext = find_create_ext(dev, &mdata->dc_sent_extents, start, length); + if (!ext) { + dev_err(dev, "Extent %#llx-%#llx not found\n", + start, start + length); + return -ENOMEM; + } + ext = xa_erase(&mdata->dc_sent_extents, ext->dpa_start); + return xa_insert(&mdata->dc_accepted_exts, start, ext, GFP_KERNEL); +} + +static void release_dc_ext(void *md) +{ + struct cxl_mockmem_data *mdata = md; + + xa_destroy(&mdata->dc_fm_extents); + xa_destroy(&mdata->dc_sent_extents); + xa_destroy(&mdata->dc_accepted_exts); +} + +/* Pretend to have some previous accepted extents */ +struct pre_ext_info { + u64 offset; + u64 length; +} pre_ext_info[] = { + { + .offset = SZ_128M, + .length = SZ_64M, + }, + { + .offset = SZ_256M, + .length = SZ_64M, + }, +}; + +static int devm_add_sent_extent(struct device *dev, u64 start, u64 length, + const char *tag, bool shared) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + + lockdep_assert_held(&mdata->ext_lock); + return __devm_add_extent(dev, &mdata->dc_sent_extents, start, length, + tag, shared); +} + +static int inject_prev_extents(struct device *dev, u64 base_dpa) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + int rc; + + dev_dbg(dev, "Adding %ld pre-extents for testing\n", + ARRAY_SIZE(pre_ext_info)); + + guard(mutex)(&mdata->ext_lock); + for (int i = 0; i < ARRAY_SIZE(pre_ext_info); i++) { + u64 ext_dpa = base_dpa + pre_ext_info[i].offset; + u64 ext_len = pre_ext_info[i].length; + + dev_dbg(dev, "Adding pre-extent DPA:%#llx LEN:%#llx\n", + ext_dpa, ext_len); + + rc = devm_add_sent_extent(dev, ext_dpa, ext_len, "", false); + if (rc) { + dev_err(dev, "Failed to add pre-extent DPA:%#llx LEN:%#llx; %d\n", + ext_dpa, ext_len, rc); + return rc; + } + + rc = dc_accept_extent(dev, ext_dpa, ext_len); + if (rc) + return rc; + } + return 0; +} + +static int cxl_mock_dc_region_setup(struct device *dev) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + u64 base_dpa = BASE_DYNAMIC_CAP_DPA; + u32 dsmad_handle = 0xFADE; + u64 decode_length = SZ_512M; + u64 block_size = SZ_512; + u64 length = SZ_512M; + int rc; + + mutex_init(&mdata->ext_lock); + xa_init(&mdata->dc_fm_extents); + xa_init(&mdata->dc_sent_extents); + xa_init(&mdata->dc_accepted_exts); + + rc = devm_add_action_or_reset(dev, release_dc_ext, mdata); + if (rc) + return rc; + + for (int i = 0; i < NUM_MOCK_DC_REGIONS; i++) { + struct cxl_dc_region_config *conf = &mdata->dc_regions[i]; + + dev_dbg(dev, "Creating DC region DC%d DPA:%#llx LEN:%#llx\n", + i, base_dpa, length); + + conf->region_base = cpu_to_le64(base_dpa); + conf->region_decode_length = cpu_to_le64(decode_length / + CXL_CAPACITY_MULTIPLIER); + conf->region_length = cpu_to_le64(length); + conf->region_block_size = cpu_to_le64(block_size); + conf->region_dsmad_handle = cpu_to_le32(dsmad_handle); + dsmad_handle++; + + rc = inject_prev_extents(dev, base_dpa); + if (rc) { + dev_err(dev, "Failed to add pre-extents for DC%d\n", i); + return rc; + } + + base_dpa += decode_length; + } + + return 0; +} + static int mock_gsl(struct cxl_mbox_cmd *cmd) { if (cmd->size_out < sizeof(mock_gsl_payload)) @@ -1383,6 +1658,192 @@ static int mock_activate_fw(struct cxl_mockmem_data *mdata, return -EINVAL; } +static int mock_get_dc_config(struct device *dev, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_get_dc_config_in *dc_config = cmd->payload_in; + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + u8 region_requested, region_start_idx, region_ret_cnt; + struct cxl_mbox_get_dc_config_out *resp; + int i; + + region_requested = min(dc_config->region_count, NUM_MOCK_DC_REGIONS); + + if (cmd->size_out < struct_size(resp, region, region_requested)) + return -EINVAL; + + memset(cmd->payload_out, 0, cmd->size_out); + resp = cmd->payload_out; + + region_start_idx = dc_config->start_region_index; + region_ret_cnt = 0; + for (i = 0; i < NUM_MOCK_DC_REGIONS; i++) { + if (i >= region_start_idx) { + memcpy(&resp->region[region_ret_cnt], + &mdata->dc_regions[i], + sizeof(resp->region[region_ret_cnt])); + region_ret_cnt++; + } + } + resp->avail_region_count = NUM_MOCK_DC_REGIONS; + resp->regions_returned = i; + + dev_dbg(dev, "Returning %d dc regions\n", region_ret_cnt); + return 0; +} + +static int mock_get_dc_extent_list(struct device *dev, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_get_extent_out *resp = cmd->payload_out; + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_mbox_get_extent_in *get = cmd->payload_in; + u32 total_avail = 0, total_ret = 0; + struct cxl_extent_data *ext; + u32 ext_count, start_idx; + unsigned long i; + + ext_count = le32_to_cpu(get->extent_cnt); + start_idx = le32_to_cpu(get->start_extent_index); + + memset(resp, 0, sizeof(*resp)); + + guard(mutex)(&mdata->ext_lock); + /* + * Total available needs to be calculated and returned regardless of + * how many can actually be returned. + */ + xa_for_each(&mdata->dc_accepted_exts, i, ext) + total_avail++; + + if (start_idx > total_avail) + return -EINVAL; + + xa_for_each(&mdata->dc_accepted_exts, i, ext) { + if (total_ret >= ext_count) + break; + + if (total_ret >= start_idx) { + resp->extent[total_ret].start_dpa = + cpu_to_le64(ext->dpa_start); + resp->extent[total_ret].length = + cpu_to_le64(ext->length); + memcpy(&resp->extent[total_ret].tag, ext->tag, + sizeof(resp->extent[total_ret])); + total_ret++; + } + } + + resp->returned_extent_count = cpu_to_le32(total_ret); + resp->total_extent_count = cpu_to_le32(total_avail); + resp->generation_num = cpu_to_le32(mdata->dc_ext_generation); + + dev_dbg(dev, "Returning %d extents of %d total\n", + total_ret, total_avail); + + return 0; +} + +static void dc_clear_sent(struct device *dev) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_extent_data *ext; + unsigned long index; + + lockdep_assert_held(&mdata->ext_lock); + + /* Any extents not accepted must be cleared */ + xa_for_each(&mdata->dc_sent_extents, index, ext) { + dev_dbg(dev, "Host rejected extent %#llx\n", ext->dpa_start); + xa_erase(&mdata->dc_sent_extents, ext->dpa_start); + } +} + +static int mock_add_dc_response(struct device *dev, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_mbox_dc_response *req = cmd->payload_in; + u32 list_size = le32_to_cpu(req->extent_list_size); + + guard(mutex)(&mdata->ext_lock); + for (int i = 0; i < list_size; i++) { + u64 start = le64_to_cpu(req->extent_list[i].dpa_start); + u64 length = le64_to_cpu(req->extent_list[i].length); + int rc; + + rc = dc_accept_extent(dev, start, length); + if (rc) + return rc; + } + + dc_clear_sent(dev); + return 0; +} + +static void dc_delete_extent(struct device *dev, unsigned long long start, + unsigned long long length) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + unsigned long long end = start + length; + struct cxl_extent_data *ext; + unsigned long index; + + dev_dbg(dev, "Deleting extent at %#llx len:%#llx\n", start, length); + + guard(mutex)(&mdata->ext_lock); + xa_for_each(&mdata->dc_fm_extents, index, ext) { + u64 extent_end = ext->dpa_start + ext->length; + + /* + * Any extent which 'touches' the released delete range will be + * removed. + */ + if ((start <= ext->dpa_start && ext->dpa_start < end) || + (start <= extent_end && extent_end < end)) + xa_erase(&mdata->dc_fm_extents, ext->dpa_start); + } + + /* + * If the extent was accepted let it be for the host to drop + * later. + */ +} + +static int release_accepted_extent(struct device *dev, u64 start, u64 length) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_extent_data *ext; + + guard(mutex)(&mdata->ext_lock); + ext = find_create_ext(dev, &mdata->dc_accepted_exts, start, length); + if (!ext) { + dev_err(dev, "Extent %#llx not in accepted state\n", start); + return -EINVAL; + } + xa_erase(&mdata->dc_accepted_exts, ext->dpa_start); + mdata->dc_ext_generation++; + + return 0; +} + +static int mock_dc_release(struct device *dev, + struct cxl_mbox_cmd *cmd) +{ + struct cxl_mbox_dc_response *req = cmd->payload_in; + u32 list_size = le32_to_cpu(req->extent_list_size); + + for (int i = 0; i < list_size; i++) { + u64 start = le64_to_cpu(req->extent_list[i].dpa_start); + u64 length = le64_to_cpu(req->extent_list[i].length); + + dev_dbg(dev, "Extent %#llx released by host\n", start); + release_accepted_extent(dev, start, length); + } + + return 0; +} + static int cxl_mock_mbox_send(struct cxl_mailbox *cxl_mbox, struct cxl_mbox_cmd *cmd) { @@ -1468,6 +1929,18 @@ static int cxl_mock_mbox_send(struct cxl_mailbox *cxl_mbox, case CXL_MBOX_OP_ACTIVATE_FW: rc = mock_activate_fw(mdata, cmd); break; + case CXL_MBOX_OP_GET_DC_CONFIG: + rc = mock_get_dc_config(dev, cmd); + break; + case CXL_MBOX_OP_GET_DC_EXTENT_LIST: + rc = mock_get_dc_extent_list(dev, cmd); + break; + case CXL_MBOX_OP_ADD_DC_RESPONSE: + rc = mock_add_dc_response(dev, cmd); + break; + case CXL_MBOX_OP_RELEASE_DC: + rc = mock_dc_release(dev, cmd); + break; default: break; } @@ -1538,6 +2011,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) return -ENOMEM; dev_set_drvdata(dev, mdata); + rc = cxl_mock_dc_region_setup(dev); + if (rc) + return rc; + mdata->lsa = vmalloc(LSA_SIZE); if (!mdata->lsa) return -ENOMEM; @@ -1591,6 +2068,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) if (rc) return rc; + rc = cxl_dev_dynamic_capacity_identify(mds); + if (rc) + return rc; + rc = cxl_mem_create_range_info(mds); if (rc) return rc; @@ -1706,11 +2187,281 @@ static ssize_t sanitize_timeout_store(struct device *dev, static DEVICE_ATTR_RW(sanitize_timeout); +/* Return if the proposed extent would break the test code */ +static bool new_extent_valid(struct device *dev, size_t new_start, + size_t new_len) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_extent_data *extent; + size_t new_end, i; + + if (!new_len) + return false; + + new_end = new_start + new_len; + + dev_dbg(dev, "New extent %zx-%zx\n", new_start, new_end); + + guard(mutex)(&mdata->ext_lock); + dev_dbg(dev, "Checking extents starts...\n"); + xa_for_each(&mdata->dc_fm_extents, i, extent) { + if (extent->dpa_start == new_start) + return false; + } + + dev_dbg(dev, "Checking sent extents starts...\n"); + xa_for_each(&mdata->dc_sent_extents, i, extent) { + if (extent->dpa_start == new_start) + return false; + } + + dev_dbg(dev, "Checking accepted extents starts...\n"); + xa_for_each(&mdata->dc_accepted_exts, i, extent) { + if (extent->dpa_start == new_start) + return false; + } + + return true; +} + +struct cxl_test_dcd { + uuid_t id; + struct cxl_event_dcd rec; +} __packed; + +struct cxl_test_dcd dcd_event_rec_template = { + .id = CXL_EVENT_DC_EVENT_UUID, + .rec = { + .hdr = { + .length = sizeof(struct cxl_test_dcd), + }, + }, +}; + +static int log_dc_event(struct cxl_mockmem_data *mdata, enum dc_event type, + u64 start, u64 length, const char *tag_str, bool more) +{ + struct device *dev = mdata->mds->cxlds.dev; + struct cxl_test_dcd *dcd_event; + + dev_dbg(dev, "mock device log event %d\n", type); + + dcd_event = devm_kmemdup(dev, &dcd_event_rec_template, + sizeof(*dcd_event), GFP_KERNEL); + if (!dcd_event) + return -ENOMEM; + + dcd_event->rec.flags = 0; + if (more) + dcd_event->rec.flags |= CXL_DCD_EVENT_MORE; + dcd_event->rec.event_type = type; + dcd_event->rec.extent.start_dpa = cpu_to_le64(start); + dcd_event->rec.extent.length = cpu_to_le64(length); + memcpy(dcd_event->rec.extent.tag, tag_str, + min(sizeof(dcd_event->rec.extent.tag), + strlen(tag_str))); + + mes_add_event(mdata, CXL_EVENT_TYPE_DCD, + (struct cxl_event_record_raw *)dcd_event); + + /* Fake the irq */ + cxl_mem_get_event_records(mdata->mds, CXLDEV_EVENT_STATUS_DCD); + + return 0; +} + +static void mark_extent_sent(struct device *dev, unsigned long long start) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + struct cxl_extent_data *ext; + + guard(mutex)(&mdata->ext_lock); + ext = xa_erase(&mdata->dc_fm_extents, start); + if (xa_insert(&mdata->dc_sent_extents, ext->dpa_start, ext, GFP_KERNEL)) + dev_err(dev, "Failed to mark extent %#llx sent\n", ext->dpa_start); +} + +/* + * Format ::: + * + * start and length must be a multiple of the configured region block size. + * Tag can be any string up to 16 bytes. + * + * Extents must be exclusive of other extents + * + * If the more flag is specified it is expected that an additional extent will + * be specified without the more flag to complete the test transaction with the + * host. + */ +static ssize_t __dc_inject_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + bool shared) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + unsigned long long start, length, more; + char *len_str, *tag_str, *more_str; + size_t buf_len = count; + int rc; + + char *start_str __free(kfree) = kstrdup(buf, GFP_KERNEL); + if (!start_str) + return -ENOMEM; + + len_str = strnchr(start_str, buf_len, ':'); + if (!len_str) { + dev_err(dev, "Extent failed to find len_str: %s\n", start_str); + return -EINVAL; + } + + *len_str = '\0'; + len_str += 1; + buf_len -= strlen(start_str); + + tag_str = strnchr(len_str, buf_len, ':'); + if (!tag_str) { + dev_err(dev, "Extent failed to find tag_str: %s\n", len_str); + return -EINVAL; + } + *tag_str = '\0'; + tag_str += 1; + + more_str = strnchr(tag_str, buf_len, ':'); + if (!more_str) { + dev_err(dev, "Extent failed to find more_str: %s\n", tag_str); + return -EINVAL; + } + *more_str = '\0'; + more_str += 1; + + if (kstrtoull(start_str, 0, &start)) { + dev_err(dev, "Extent failed to parse start: %s\n", start_str); + return -EINVAL; + } + + if (kstrtoull(len_str, 0, &length)) { + dev_err(dev, "Extent failed to parse length: %s\n", len_str); + return -EINVAL; + } + + if (kstrtoull(more_str, 0, &more)) { + dev_err(dev, "Extent failed to parse more: %s\n", more_str); + return -EINVAL; + } + + if (!new_extent_valid(dev, start, length)) + return -EINVAL; + + rc = devm_add_fm_extent(dev, start, length, tag_str, shared); + if (rc) { + dev_err(dev, "Failed to add extent DPA:%#llx LEN:%#llx; %d\n", + start, length, rc); + return rc; + } + + mark_extent_sent(dev, start); + rc = log_dc_event(mdata, DCD_ADD_CAPACITY, start, length, tag_str, more); + if (rc) { + dev_err(dev, "Failed to add event %d\n", rc); + return rc; + } + + return count; +} + +static ssize_t dc_inject_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return __dc_inject_extent_store(dev, attr, buf, count, false); +} +static DEVICE_ATTR_WO(dc_inject_extent); + +static ssize_t dc_inject_shared_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return __dc_inject_extent_store(dev, attr, buf, count, true); +} +static DEVICE_ATTR_WO(dc_inject_shared_extent); + +static ssize_t __dc_del_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count, + enum dc_event type) +{ + struct cxl_mockmem_data *mdata = dev_get_drvdata(dev); + unsigned long long start, length; + char *len_str; + int rc; + + char *start_str __free(kfree) = kstrdup(buf, GFP_KERNEL); + if (!start_str) + return -ENOMEM; + + len_str = strnchr(start_str, count, ':'); + if (!len_str) { + dev_err(dev, "Failed to find len_str: %s\n", start_str); + return -EINVAL; + } + *len_str = '\0'; + len_str += 1; + + if (kstrtoull(start_str, 0, &start)) { + dev_err(dev, "Failed to parse start: %s\n", start_str); + return -EINVAL; + } + + if (kstrtoull(len_str, 0, &length)) { + dev_err(dev, "Failed to parse length: %s\n", len_str); + return -EINVAL; + } + + dc_delete_extent(dev, start, length); + + if (type == DCD_FORCED_CAPACITY_RELEASE) + dev_dbg(dev, "Forcing delete of extent %#llx len:%#llx\n", + start, length); + + rc = log_dc_event(mdata, type, start, length, "", false); + if (rc) { + dev_err(dev, "Failed to add event %d\n", rc); + return rc; + } + + return count; +} + +/* + * Format : + */ +static ssize_t dc_del_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return __dc_del_extent_store(dev, attr, buf, count, + DCD_RELEASE_CAPACITY); +} +static DEVICE_ATTR_WO(dc_del_extent); + +static ssize_t dc_force_del_extent_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return __dc_del_extent_store(dev, attr, buf, count, + DCD_FORCED_CAPACITY_RELEASE); +} +static DEVICE_ATTR_WO(dc_force_del_extent); + static struct attribute *cxl_mock_mem_attrs[] = { &dev_attr_security_lock.attr, &dev_attr_event_trigger.attr, &dev_attr_fw_buf_checksum.attr, &dev_attr_sanitize_timeout.attr, + &dev_attr_dc_inject_extent.attr, + &dev_attr_dc_inject_shared_extent.attr, + &dev_attr_dc_del_extent.attr, + &dev_attr_dc_force_del_extent.attr, NULL }; ATTRIBUTE_GROUPS(cxl_mock_mem);