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

Merge tag 'cxl-for-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl

Pull cxl updates from Dan Williams:
"Compute Express Link (CXL) updates for 6.0:

- Introduce a 'struct cxl_region' object with support for
provisioning and assembling persistent memory regions.

- Introduce alloc_free_mem_region() to accompany the existing
request_free_mem_region() as a method to allocate physical memory
capacity out of an existing resource.

- Export insert_resource_expand_to_fit() for the CXL subsystem to
late-publish CXL platform windows in iomem_resource.

- Add a polled mode PCI DOE (Data Object Exchange) driver service and
use it in cxl_pci to retrieve the CDAT (Coherent Device Attribute
Table)"

* tag 'cxl-for-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl: (74 commits)
cxl/hdm: Fix skip allocations vs multiple pmem allocations
cxl/region: Disallow region granularity != window granularity
cxl/region: Fix x1 interleave to greater than x1 interleave routing
cxl/region: Move HPA setup to cxl_region_attach()
cxl/region: Fix decoder interleave programming
Documentation: cxl: remove dangling kernel-doc reference
cxl/region: describe targets and nr_targets members of cxl_region_params
cxl/regions: add padding for cxl_rr_ep_add nested lists
cxl/region: Fix IS_ERR() vs NULL check
cxl/region: Fix region reference target accounting
cxl/region: Fix region commit uninitialized variable warning
cxl/region: Fix port setup uninitialized variable warnings
cxl/region: Stop initializing interleave granularity
cxl/hdm: Fix DPA reservation vs cxl_endpoint_decoder lifetime
cxl/acpi: Minimize granularity for x1 interleaves
cxl/region: Delete 'region' attribute from root decoders
cxl/acpi: Autoload driver for 'cxl_acpi' test devices
cxl/region: decrement ->nr_targets on error in cxl_region_attach()
cxl/region: prevent underflow in ways_to_cxl()
cxl/region: uninitialized variable in alloc_hpa()
...

+5508 -586
+1
.clang-format
··· 516 516 - 'of_property_for_each_string' 517 517 - 'of_property_for_each_u32' 518 518 - 'pci_bus_for_each_resource' 519 + - 'pci_doe_for_each_off' 519 520 - 'pcl_for_each_chunk' 520 521 - 'pcl_for_each_segment' 521 522 - 'pcm_for_each_format'
+265 -40
Documentation/ABI/testing/sysfs-bus-cxl
··· 7 7 all descendant memdevs for unbind. Writing '1' to this attribute 8 8 flushes that work. 9 9 10 + 10 11 What: /sys/bus/cxl/devices/memX/firmware_version 11 12 Date: December, 2020 12 13 KernelVersion: v5.12 ··· 16 15 (RO) "FW Revision" string as reported by the Identify 17 16 Memory Device Output Payload in the CXL-2.0 18 17 specification. 18 + 19 19 20 20 What: /sys/bus/cxl/devices/memX/ram/size 21 21 Date: December, 2020 ··· 27 25 identically named field in the Identify Memory Device Output 28 26 Payload in the CXL-2.0 specification. 29 27 28 + 30 29 What: /sys/bus/cxl/devices/memX/pmem/size 31 30 Date: December, 2020 32 31 KernelVersion: v5.12 ··· 36 33 (RO) "Persistent Only Capacity" as bytes. Represents the 37 34 identically named field in the Identify Memory Device Output 38 35 Payload in the CXL-2.0 specification. 36 + 39 37 40 38 What: /sys/bus/cxl/devices/memX/serial 41 39 Date: January, 2022 ··· 47 43 capability. Mandatory for CXL devices, see CXL 2.0 8.1.12.2 48 44 Memory Device PCIe Capabilities and Extended Capabilities. 49 45 46 + 50 47 What: /sys/bus/cxl/devices/memX/numa_node 51 48 Date: January, 2022 52 49 KernelVersion: v5.18 ··· 57 52 host PCI device for this memory device, emit the CPU node 58 53 affinity for this device. 59 54 55 + 60 56 What: /sys/bus/cxl/devices/*/devtype 61 57 Date: June, 2021 62 58 KernelVersion: v5.14 63 59 Contact: linux-cxl@vger.kernel.org 64 60 Description: 65 - CXL device objects export the devtype attribute which mirrors 66 - the same value communicated in the DEVTYPE environment variable 67 - for uevents for devices on the "cxl" bus. 61 + (RO) CXL device objects export the devtype attribute which 62 + mirrors the same value communicated in the DEVTYPE environment 63 + variable for uevents for devices on the "cxl" bus. 64 + 68 65 69 66 What: /sys/bus/cxl/devices/*/modalias 70 67 Date: December, 2021 71 68 KernelVersion: v5.18 72 69 Contact: linux-cxl@vger.kernel.org 73 70 Description: 74 - CXL device objects export the modalias attribute which mirrors 75 - the same value communicated in the MODALIAS environment variable 76 - for uevents for devices on the "cxl" bus. 71 + (RO) CXL device objects export the modalias attribute which 72 + mirrors the same value communicated in the MODALIAS environment 73 + variable for uevents for devices on the "cxl" bus. 74 + 77 75 78 76 What: /sys/bus/cxl/devices/portX/uport 79 77 Date: June, 2021 80 78 KernelVersion: v5.14 81 79 Contact: linux-cxl@vger.kernel.org 82 80 Description: 83 - CXL port objects are enumerated from either a platform firmware 84 - device (ACPI0017 and ACPI0016) or PCIe switch upstream port with 85 - CXL component registers. The 'uport' symlink connects the CXL 86 - portX object to the device that published the CXL port 81 + (RO) CXL port objects are enumerated from either a platform 82 + firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream 83 + port with CXL component registers. The 'uport' symlink connects 84 + the CXL portX object to the device that published the CXL port 87 85 capability. 86 + 88 87 89 88 What: /sys/bus/cxl/devices/portX/dportY 90 89 Date: June, 2021 91 90 KernelVersion: v5.14 92 91 Contact: linux-cxl@vger.kernel.org 93 92 Description: 94 - CXL port objects are enumerated from either a platform firmware 95 - device (ACPI0017 and ACPI0016) or PCIe switch upstream port with 96 - CXL component registers. The 'dportY' symlink identifies one or 97 - more downstream ports that the upstream port may target in its 98 - decode of CXL memory resources. The 'Y' integer reflects the 99 - hardware port unique-id used in the hardware decoder target 100 - list. 93 + (RO) CXL port objects are enumerated from either a platform 94 + firmware device (ACPI0017 and ACPI0016) or PCIe switch upstream 95 + port with CXL component registers. The 'dportY' symlink 96 + identifies one or more downstream ports that the upstream port 97 + may target in its decode of CXL memory resources. The 'Y' 98 + integer reflects the hardware port unique-id used in the 99 + hardware decoder target list. 100 + 101 101 102 102 What: /sys/bus/cxl/devices/decoderX.Y 103 103 Date: June, 2021 104 104 KernelVersion: v5.14 105 105 Contact: linux-cxl@vger.kernel.org 106 106 Description: 107 - CXL decoder objects are enumerated from either a platform 107 + (RO) CXL decoder objects are enumerated from either a platform 108 108 firmware description, or a CXL HDM decoder register set in a 109 109 PCIe device (see CXL 2.0 section 8.2.5.12 CXL HDM Decoder 110 110 Capability Structure). The 'X' in decoderX.Y represents the 111 111 cxl_port container of this decoder, and 'Y' represents the 112 112 instance id of a given decoder resource. 113 113 114 + 114 115 What: /sys/bus/cxl/devices/decoderX.Y/{start,size} 115 116 Date: June, 2021 116 117 KernelVersion: v5.14 117 118 Contact: linux-cxl@vger.kernel.org 118 119 Description: 119 - The 'start' and 'size' attributes together convey the physical 120 - address base and number of bytes mapped in the decoder's decode 121 - window. For decoders of devtype "cxl_decoder_root" the address 122 - range is fixed. For decoders of devtype "cxl_decoder_switch" the 123 - address is bounded by the decode range of the cxl_port ancestor 124 - of the decoder's cxl_port, and dynamically updates based on the 125 - active memory regions in that address space. 120 + (RO) The 'start' and 'size' attributes together convey the 121 + physical address base and number of bytes mapped in the 122 + decoder's decode window. For decoders of devtype 123 + "cxl_decoder_root" the address range is fixed. For decoders of 124 + devtype "cxl_decoder_switch" the address is bounded by the 125 + decode range of the cxl_port ancestor of the decoder's cxl_port, 126 + and dynamically updates based on the active memory regions in 127 + that address space. 128 + 126 129 127 130 What: /sys/bus/cxl/devices/decoderX.Y/locked 128 131 Date: June, 2021 129 132 KernelVersion: v5.14 130 133 Contact: linux-cxl@vger.kernel.org 131 134 Description: 132 - CXL HDM decoders have the capability to lock the configuration 133 - until the next device reset. For decoders of devtype 134 - "cxl_decoder_root" there is no standard facility to unlock them. 135 - For decoders of devtype "cxl_decoder_switch" a secondary bus 136 - reset, of the PCIe bridge that provides the bus for this 137 - decoders uport, unlocks / resets the decoder. 135 + (RO) CXL HDM decoders have the capability to lock the 136 + configuration until the next device reset. For decoders of 137 + devtype "cxl_decoder_root" there is no standard facility to 138 + unlock them. For decoders of devtype "cxl_decoder_switch" a 139 + secondary bus reset, of the PCIe bridge that provides the bus 140 + for this decoders uport, unlocks / resets the decoder. 141 + 138 142 139 143 What: /sys/bus/cxl/devices/decoderX.Y/target_list 140 144 Date: June, 2021 141 145 KernelVersion: v5.14 142 146 Contact: linux-cxl@vger.kernel.org 143 147 Description: 144 - Display a comma separated list of the current decoder target 145 - configuration. The list is ordered by the current configured 146 - interleave order of the decoder's dport instances. Each entry in 147 - the list is a dport id. 148 + (RO) Display a comma separated list of the current decoder 149 + target configuration. The list is ordered by the current 150 + configured interleave order of the decoder's dport instances. 151 + Each entry in the list is a dport id. 152 + 148 153 149 154 What: /sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3} 150 155 Date: June, 2021 151 156 KernelVersion: v5.14 152 157 Contact: linux-cxl@vger.kernel.org 153 158 Description: 154 - When a CXL decoder is of devtype "cxl_decoder_root", it 159 + (RO) When a CXL decoder is of devtype "cxl_decoder_root", it 155 160 represents a fixed memory window identified by platform 156 161 firmware. A fixed window may only support a subset of memory 157 162 types. The 'cap_*' attributes indicate whether persistent 158 163 memory, volatile memory, accelerator memory, and / or expander 159 164 memory may be mapped behind this decoder's memory window. 160 165 166 + 161 167 What: /sys/bus/cxl/devices/decoderX.Y/target_type 162 168 Date: June, 2021 163 169 KernelVersion: v5.14 164 170 Contact: linux-cxl@vger.kernel.org 165 171 Description: 166 - When a CXL decoder is of devtype "cxl_decoder_switch", it can 167 - optionally decode either accelerator memory (type-2) or expander 168 - memory (type-3). The 'target_type' attribute indicates the 169 - current setting which may dynamically change based on what 172 + (RO) When a CXL decoder is of devtype "cxl_decoder_switch", it 173 + can optionally decode either accelerator memory (type-2) or 174 + expander memory (type-3). The 'target_type' attribute indicates 175 + the current setting which may dynamically change based on what 170 176 memory regions are activated in this decode hierarchy. 177 + 178 + 179 + What: /sys/bus/cxl/devices/endpointX/CDAT 180 + Date: July, 2022 181 + KernelVersion: v5.20 182 + Contact: linux-cxl@vger.kernel.org 183 + Description: 184 + (RO) If this sysfs entry is not present no DOE mailbox was 185 + found to support CDAT data. If it is present and the length of 186 + the data is 0 reading the CDAT data failed. Otherwise the CDAT 187 + data is reported. 188 + 189 + 190 + What: /sys/bus/cxl/devices/decoderX.Y/mode 191 + Date: May, 2022 192 + KernelVersion: v5.20 193 + Contact: linux-cxl@vger.kernel.org 194 + Description: 195 + (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it 196 + translates from a host physical address range, to a device local 197 + address range. Device-local address ranges are further split 198 + into a 'ram' (volatile memory) range and 'pmem' (persistent 199 + memory) range. The 'mode' attribute emits one of 'ram', 'pmem', 200 + 'mixed', or 'none'. The 'mixed' indication is for error cases 201 + when a decoder straddles the volatile/persistent partition 202 + boundary, and 'none' indicates the decoder is not actively 203 + decoding, or no DPA allocation policy has been set. 204 + 205 + 'mode' can be written, when the decoder is in the 'disabled' 206 + state, with either 'ram' or 'pmem' to set the boundaries for the 207 + next allocation. 208 + 209 + 210 + What: /sys/bus/cxl/devices/decoderX.Y/dpa_resource 211 + Date: May, 2022 212 + KernelVersion: v5.20 213 + Contact: linux-cxl@vger.kernel.org 214 + Description: 215 + (RO) When a CXL decoder is of devtype "cxl_decoder_endpoint", 216 + and its 'dpa_size' attribute is non-zero, this attribute 217 + indicates the device physical address (DPA) base address of the 218 + allocation. 219 + 220 + 221 + What: /sys/bus/cxl/devices/decoderX.Y/dpa_size 222 + Date: May, 2022 223 + KernelVersion: v5.20 224 + Contact: linux-cxl@vger.kernel.org 225 + Description: 226 + (RW) When a CXL decoder is of devtype "cxl_decoder_endpoint" it 227 + translates from a host physical address range, to a device local 228 + address range. The range, base address plus length in bytes, of 229 + DPA allocated to this decoder is conveyed in these 2 attributes. 230 + Allocations can be mutated as long as the decoder is in the 231 + disabled state. A write to 'dpa_size' releases the previous DPA 232 + allocation and then attempts to allocate from the free capacity 233 + in the device partition referred to by 'decoderX.Y/mode'. 234 + Allocate and free requests can only be performed on the highest 235 + instance number disabled decoder with non-zero size. I.e. 236 + allocations are enforced to occur in increasing 'decoderX.Y/id' 237 + order and frees are enforced to occur in decreasing 238 + 'decoderX.Y/id' order. 239 + 240 + 241 + What: /sys/bus/cxl/devices/decoderX.Y/interleave_ways 242 + Date: May, 2022 243 + KernelVersion: v5.20 244 + Contact: linux-cxl@vger.kernel.org 245 + Description: 246 + (RO) The number of targets across which this decoder's host 247 + physical address (HPA) memory range is interleaved. The device 248 + maps every Nth block of HPA (of size == 249 + 'interleave_granularity') to consecutive DPA addresses. The 250 + decoder's position in the interleave is determined by the 251 + device's (endpoint or switch) switch ancestry. For root 252 + decoders their interleave is specified by platform firmware and 253 + they only specify a downstream target order for host bridges. 254 + 255 + 256 + What: /sys/bus/cxl/devices/decoderX.Y/interleave_granularity 257 + Date: May, 2022 258 + KernelVersion: v5.20 259 + Contact: linux-cxl@vger.kernel.org 260 + Description: 261 + (RO) The number of consecutive bytes of host physical address 262 + space this decoder claims at address N before the decode rotates 263 + to the next target in the interleave at address N + 264 + interleave_granularity (assuming N is aligned to 265 + interleave_granularity). 266 + 267 + 268 + What: /sys/bus/cxl/devices/decoderX.Y/create_pmem_region 269 + Date: May, 2022 270 + KernelVersion: v5.20 271 + Contact: linux-cxl@vger.kernel.org 272 + Description: 273 + (RW) Write a string in the form 'regionZ' to start the process 274 + of defining a new persistent memory region (interleave-set) 275 + within the decode range bounded by root decoder 'decoderX.Y'. 276 + The value written must match the current value returned from 277 + reading this attribute. An atomic compare exchange operation is 278 + done on write to assign the requested id to a region and 279 + allocate the region-id for the next creation attempt. EBUSY is 280 + returned if the region name written does not match the current 281 + cached value. 282 + 283 + 284 + What: /sys/bus/cxl/devices/decoderX.Y/delete_region 285 + Date: May, 2022 286 + KernelVersion: v5.20 287 + Contact: linux-cxl@vger.kernel.org 288 + Description: 289 + (WO) Write a string in the form 'regionZ' to delete that region, 290 + provided it is currently idle / not bound to a driver. 291 + 292 + 293 + What: /sys/bus/cxl/devices/regionZ/uuid 294 + Date: May, 2022 295 + KernelVersion: v5.20 296 + Contact: linux-cxl@vger.kernel.org 297 + Description: 298 + (RW) Write a unique identifier for the region. This field must 299 + be set for persistent regions and it must not conflict with the 300 + UUID of another region. 301 + 302 + 303 + What: /sys/bus/cxl/devices/regionZ/interleave_granularity 304 + Date: May, 2022 305 + KernelVersion: v5.20 306 + Contact: linux-cxl@vger.kernel.org 307 + Description: 308 + (RW) Set the number of consecutive bytes each device in the 309 + interleave set will claim. The possible interleave granularity 310 + values are determined by the CXL spec and the participating 311 + devices. 312 + 313 + 314 + What: /sys/bus/cxl/devices/regionZ/interleave_ways 315 + Date: May, 2022 316 + KernelVersion: v5.20 317 + Contact: linux-cxl@vger.kernel.org 318 + Description: 319 + (RW) Configures the number of devices participating in the 320 + region is set by writing this value. Each device will provide 321 + 1/interleave_ways of storage for the region. 322 + 323 + 324 + What: /sys/bus/cxl/devices/regionZ/size 325 + Date: May, 2022 326 + KernelVersion: v5.20 327 + Contact: linux-cxl@vger.kernel.org 328 + Description: 329 + (RW) System physical address space to be consumed by the region. 330 + When written trigger the driver to allocate space out of the 331 + parent root decoder's address space. When read the size of the 332 + address space is reported and should match the span of the 333 + region's resource attribute. Size shall be set after the 334 + interleave configuration parameters. Once set it cannot be 335 + changed, only freed by writing 0. The kernel makes no guarantees 336 + that data is maintained over an address space freeing event, and 337 + there is no guarantee that a free followed by an allocate 338 + results in the same address being allocated. 339 + 340 + 341 + What: /sys/bus/cxl/devices/regionZ/resource 342 + Date: May, 2022 343 + KernelVersion: v5.20 344 + Contact: linux-cxl@vger.kernel.org 345 + Description: 346 + (RO) A region is a contiguous partition of a CXL root decoder 347 + address space. Region capacity is allocated by writing to the 348 + size attribute, the resulting physical address space determined 349 + by the driver is reflected here. It is therefore not useful to 350 + read this before writing a value to the size attribute. 351 + 352 + 353 + What: /sys/bus/cxl/devices/regionZ/target[0..N] 354 + Date: May, 2022 355 + KernelVersion: v5.20 356 + Contact: linux-cxl@vger.kernel.org 357 + Description: 358 + (RW) Write an endpoint decoder object name to 'targetX' where X 359 + is the intended position of the endpoint device in the region 360 + interleave and N is the 'interleave_ways' setting for the 361 + region. ENXIO is returned if the write results in an impossible 362 + to map decode scenario, like the endpoint is unreachable at that 363 + position relative to the root decoder interleave. EBUSY is 364 + returned if the position in the region is already occupied, or 365 + if the region is not in a state to accept interleave 366 + configuration changes. EINVAL is returned if the object name is 367 + not an endpoint decoder. Once all positions have been 368 + successfully written a final validation for decode conflicts is 369 + performed before activating the region. 370 + 371 + 372 + What: /sys/bus/cxl/devices/regionZ/commit 373 + Date: May, 2022 374 + KernelVersion: v5.20 375 + Contact: linux-cxl@vger.kernel.org 376 + Description: 377 + (RW) Write a boolean 'true' string value to this attribute to 378 + trigger the region to transition from the software programmed 379 + state to the actively decoding in hardware state. The commit 380 + operation in addition to validating that the region is in proper 381 + configured state, validates that the decoders are being 382 + committed in spec mandated order (last committed decoder id + 383 + 1), and checks that the hardware accepts the commit request. 384 + Reading this value indicates whether the region is committed or 385 + not.
+8
Documentation/driver-api/cxl/memory-devices.rst
··· 362 362 .. kernel-doc:: drivers/cxl/core/mbox.c 363 363 :doc: cxl mbox 364 364 365 + CXL Regions 366 + ----------- 367 + .. kernel-doc:: drivers/cxl/core/region.c 368 + :doc: cxl core region 369 + 370 + .. kernel-doc:: drivers/cxl/core/region.c 371 + :identifiers: 372 + 365 373 External Interfaces 366 374 =================== 367 375
+1
arch/powerpc/mm/mem.c
··· 55 55 { 56 56 return hot_add_scn_to_nid(start); 57 57 } 58 + EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); 58 59 #endif 59 60 60 61 int __weak create_section_mapping(unsigned long start, unsigned long end,
+9
drivers/cxl/Kconfig
··· 2 2 menuconfig CXL_BUS 3 3 tristate "CXL (Compute Express Link) Devices Support" 4 4 depends on PCI 5 + select PCI_DOE 5 6 help 6 7 CXL is a bus that is electrically compatible with PCI Express, but 7 8 layers three protocols on that signalling (CXL.io, CXL.cache, and ··· 102 101 config CXL_SUSPEND 103 102 def_bool y 104 103 depends on SUSPEND && CXL_MEM 104 + 105 + config CXL_REGION 106 + bool 107 + default CXL_BUS 108 + # For MAX_PHYSMEM_BITS 109 + depends on SPARSEMEM 110 + select MEMREGION 111 + select GET_FREE_REGION 105 112 106 113 endif
+217 -26
drivers/cxl/acpi.c
··· 9 9 #include "cxlpci.h" 10 10 #include "cxl.h" 11 11 12 - /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */ 13 - #define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways) 14 - #define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8) 15 - 16 12 static unsigned long cfmws_to_decoder_flags(int restrictions) 17 13 { 18 14 unsigned long flags = CXL_DECODER_F_ENABLE; ··· 30 34 static int cxl_acpi_cfmws_verify(struct device *dev, 31 35 struct acpi_cedt_cfmws *cfmws) 32 36 { 33 - int expected_len; 37 + int rc, expected_len; 38 + unsigned int ways; 34 39 35 40 if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO) { 36 41 dev_err(dev, "CFMWS Unsupported Interleave Arithmetic\n"); ··· 48 51 return -EINVAL; 49 52 } 50 53 51 - if (CFMWS_INTERLEAVE_WAYS(cfmws) > CXL_DECODER_MAX_INTERLEAVE) { 52 - dev_err(dev, "CFMWS Interleave Ways (%d) too large\n", 53 - CFMWS_INTERLEAVE_WAYS(cfmws)); 54 + rc = cxl_to_ways(cfmws->interleave_ways, &ways); 55 + if (rc) { 56 + dev_err(dev, "CFMWS Interleave Ways (%d) invalid\n", 57 + cfmws->interleave_ways); 54 58 return -EINVAL; 55 59 } 56 60 57 - expected_len = struct_size((cfmws), interleave_targets, 58 - CFMWS_INTERLEAVE_WAYS(cfmws)); 61 + expected_len = struct_size(cfmws, interleave_targets, ways); 59 62 60 63 if (cfmws->header.length < expected_len) { 61 64 dev_err(dev, "CFMWS length %d less than expected %d\n", ··· 73 76 struct cxl_cfmws_context { 74 77 struct device *dev; 75 78 struct cxl_port *root_port; 79 + struct resource *cxl_res; 80 + int id; 76 81 }; 77 82 78 83 static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, ··· 83 84 int target_map[CXL_DECODER_MAX_INTERLEAVE]; 84 85 struct cxl_cfmws_context *ctx = arg; 85 86 struct cxl_port *root_port = ctx->root_port; 87 + struct resource *cxl_res = ctx->cxl_res; 88 + struct cxl_root_decoder *cxlrd; 86 89 struct device *dev = ctx->dev; 87 90 struct acpi_cedt_cfmws *cfmws; 88 91 struct cxl_decoder *cxld; 89 - int rc, i; 92 + unsigned int ways, i, ig; 93 + struct resource *res; 94 + int rc; 90 95 91 96 cfmws = (struct acpi_cedt_cfmws *) header; 92 97 ··· 102 99 return 0; 103 100 } 104 101 105 - for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) 102 + rc = cxl_to_ways(cfmws->interleave_ways, &ways); 103 + if (rc) 104 + return rc; 105 + rc = cxl_to_granularity(cfmws->granularity, &ig); 106 + if (rc) 107 + return rc; 108 + for (i = 0; i < ways; i++) 106 109 target_map[i] = cfmws->interleave_targets[i]; 107 110 108 - cxld = cxl_root_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws)); 109 - if (IS_ERR(cxld)) 111 + res = kzalloc(sizeof(*res), GFP_KERNEL); 112 + if (!res) 113 + return -ENOMEM; 114 + 115 + res->name = kasprintf(GFP_KERNEL, "CXL Window %d", ctx->id++); 116 + if (!res->name) 117 + goto err_name; 118 + 119 + res->start = cfmws->base_hpa; 120 + res->end = cfmws->base_hpa + cfmws->window_size - 1; 121 + res->flags = IORESOURCE_MEM; 122 + 123 + /* add to the local resource tracking to establish a sort order */ 124 + rc = insert_resource(cxl_res, res); 125 + if (rc) 126 + goto err_insert; 127 + 128 + cxlrd = cxl_root_decoder_alloc(root_port, ways); 129 + if (IS_ERR(cxlrd)) 110 130 return 0; 111 131 132 + cxld = &cxlrd->cxlsd.cxld; 112 133 cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); 113 134 cxld->target_type = CXL_DECODER_EXPANDER; 114 - cxld->platform_res = (struct resource)DEFINE_RES_MEM(cfmws->base_hpa, 115 - cfmws->window_size); 116 - cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); 117 - cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws); 135 + cxld->hpa_range = (struct range) { 136 + .start = res->start, 137 + .end = res->end, 138 + }; 139 + cxld->interleave_ways = ways; 140 + /* 141 + * Minimize the x1 granularity to advertise support for any 142 + * valid region granularity 143 + */ 144 + if (ways == 1) 145 + ig = CXL_DECODER_MIN_GRANULARITY; 146 + cxld->interleave_granularity = ig; 118 147 119 148 rc = cxl_decoder_add(cxld, target_map); 120 149 if (rc) ··· 154 119 else 155 120 rc = cxl_decoder_autoremove(dev, cxld); 156 121 if (rc) { 157 - dev_err(dev, "Failed to add decoder for %pr\n", 158 - &cxld->platform_res); 122 + dev_err(dev, "Failed to add decode range [%#llx - %#llx]\n", 123 + cxld->hpa_range.start, cxld->hpa_range.end); 159 124 return 0; 160 125 } 161 - dev_dbg(dev, "add: %s node: %d range %pr\n", dev_name(&cxld->dev), 162 - phys_to_target_node(cxld->platform_res.start), 163 - &cxld->platform_res); 126 + dev_dbg(dev, "add: %s node: %d range [%#llx - %#llx]\n", 127 + dev_name(&cxld->dev), 128 + phys_to_target_node(cxld->hpa_range.start), 129 + cxld->hpa_range.start, cxld->hpa_range.end); 164 130 165 131 return 0; 132 + 133 + err_insert: 134 + kfree(res->name); 135 + err_name: 136 + kfree(res); 137 + return -ENOMEM; 166 138 } 167 139 168 140 __mock struct acpi_device *to_cxl_host_bridge(struct device *host, ··· 217 175 if (rc) 218 176 return rc; 219 177 220 - port = devm_cxl_add_port(host, match, dport->component_reg_phys, 221 - root_port); 178 + port = devm_cxl_add_port(host, match, dport->component_reg_phys, dport); 222 179 if (IS_ERR(port)) 223 180 return PTR_ERR(port); 224 181 dev_dbg(host, "%s: add: %s\n", dev_name(match), dev_name(&port->dev)); ··· 323 282 device_lock_reset_class(dev); 324 283 } 325 284 285 + static void del_cxl_resource(struct resource *res) 286 + { 287 + kfree(res->name); 288 + kfree(res); 289 + } 290 + 291 + static void cxl_set_public_resource(struct resource *priv, struct resource *pub) 292 + { 293 + priv->desc = (unsigned long) pub; 294 + } 295 + 296 + static struct resource *cxl_get_public_resource(struct resource *priv) 297 + { 298 + return (struct resource *) priv->desc; 299 + } 300 + 301 + static void remove_cxl_resources(void *data) 302 + { 303 + struct resource *res, *next, *cxl = data; 304 + 305 + for (res = cxl->child; res; res = next) { 306 + struct resource *victim = cxl_get_public_resource(res); 307 + 308 + next = res->sibling; 309 + remove_resource(res); 310 + 311 + if (victim) { 312 + remove_resource(victim); 313 + kfree(victim); 314 + } 315 + 316 + del_cxl_resource(res); 317 + } 318 + } 319 + 320 + /** 321 + * add_cxl_resources() - reflect CXL fixed memory windows in iomem_resource 322 + * @cxl_res: A standalone resource tree where each CXL window is a sibling 323 + * 324 + * Walk each CXL window in @cxl_res and add it to iomem_resource potentially 325 + * expanding its boundaries to ensure that any conflicting resources become 326 + * children. If a window is expanded it may then conflict with a another window 327 + * entry and require the window to be truncated or trimmed. Consider this 328 + * situation: 329 + * 330 + * |-- "CXL Window 0" --||----- "CXL Window 1" -----| 331 + * |--------------- "System RAM" -------------| 332 + * 333 + * ...where platform firmware has established as System RAM resource across 2 334 + * windows, but has left some portion of window 1 for dynamic CXL region 335 + * provisioning. In this case "Window 0" will span the entirety of the "System 336 + * RAM" span, and "CXL Window 1" is truncated to the remaining tail past the end 337 + * of that "System RAM" resource. 338 + */ 339 + static int add_cxl_resources(struct resource *cxl_res) 340 + { 341 + struct resource *res, *new, *next; 342 + 343 + for (res = cxl_res->child; res; res = next) { 344 + new = kzalloc(sizeof(*new), GFP_KERNEL); 345 + if (!new) 346 + return -ENOMEM; 347 + new->name = res->name; 348 + new->start = res->start; 349 + new->end = res->end; 350 + new->flags = IORESOURCE_MEM; 351 + new->desc = IORES_DESC_CXL; 352 + 353 + /* 354 + * Record the public resource in the private cxl_res tree for 355 + * later removal. 356 + */ 357 + cxl_set_public_resource(res, new); 358 + 359 + insert_resource_expand_to_fit(&iomem_resource, new); 360 + 361 + next = res->sibling; 362 + while (next && resource_overlaps(new, next)) { 363 + if (resource_contains(new, next)) { 364 + struct resource *_next = next->sibling; 365 + 366 + remove_resource(next); 367 + del_cxl_resource(next); 368 + next = _next; 369 + } else 370 + next->start = new->end + 1; 371 + } 372 + } 373 + return 0; 374 + } 375 + 376 + static int pair_cxl_resource(struct device *dev, void *data) 377 + { 378 + struct resource *cxl_res = data; 379 + struct resource *p; 380 + 381 + if (!is_root_decoder(dev)) 382 + return 0; 383 + 384 + for (p = cxl_res->child; p; p = p->sibling) { 385 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 386 + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 387 + struct resource res = { 388 + .start = cxld->hpa_range.start, 389 + .end = cxld->hpa_range.end, 390 + .flags = IORESOURCE_MEM, 391 + }; 392 + 393 + if (resource_contains(p, &res)) { 394 + cxlrd->res = cxl_get_public_resource(p); 395 + break; 396 + } 397 + } 398 + 399 + return 0; 400 + } 401 + 326 402 static int cxl_acpi_probe(struct platform_device *pdev) 327 403 { 328 404 int rc; 405 + struct resource *cxl_res; 329 406 struct cxl_port *root_port; 330 407 struct device *host = &pdev->dev; 331 408 struct acpi_device *adev = ACPI_COMPANION(host); ··· 455 296 if (rc) 456 297 return rc; 457 298 299 + cxl_res = devm_kzalloc(host, sizeof(*cxl_res), GFP_KERNEL); 300 + if (!cxl_res) 301 + return -ENOMEM; 302 + cxl_res->name = "CXL mem"; 303 + cxl_res->start = 0; 304 + cxl_res->end = -1; 305 + cxl_res->flags = IORESOURCE_MEM; 306 + 458 307 root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); 459 308 if (IS_ERR(root_port)) 460 309 return PTR_ERR(root_port); ··· 473 306 if (rc < 0) 474 307 return rc; 475 308 309 + rc = devm_add_action_or_reset(host, remove_cxl_resources, cxl_res); 310 + if (rc) 311 + return rc; 312 + 476 313 ctx = (struct cxl_cfmws_context) { 477 314 .dev = host, 478 315 .root_port = root_port, 316 + .cxl_res = cxl_res, 479 317 }; 480 - acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx); 318 + rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx); 319 + if (rc < 0) 320 + return -ENXIO; 321 + 322 + rc = add_cxl_resources(cxl_res); 323 + if (rc) 324 + return rc; 325 + 326 + /* 327 + * Populate the root decoders with their related iomem resource, 328 + * if present 329 + */ 330 + device_for_each_child(&root_port->dev, cxl_res, pair_cxl_resource); 481 331 482 332 /* 483 333 * Root level scanned with host-bridge as dports, now scan host-bridges ··· 521 337 }; 522 338 MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids); 523 339 340 + static const struct platform_device_id cxl_test_ids[] = { 341 + { "cxl_acpi" }, 342 + { }, 343 + }; 344 + MODULE_DEVICE_TABLE(platform, cxl_test_ids); 345 + 524 346 static struct platform_driver cxl_acpi_driver = { 525 347 .probe = cxl_acpi_probe, 526 348 .driver = { 527 349 .name = KBUILD_MODNAME, 528 350 .acpi_match_table = cxl_acpi_ids, 529 351 }, 352 + .id_table = cxl_test_ids, 530 353 }; 531 354 532 355 module_platform_driver(cxl_acpi_driver);
+1
drivers/cxl/core/Makefile
··· 10 10 cxl_core-y += mbox.o 11 11 cxl_core-y += pci.o 12 12 cxl_core-y += hdm.o 13 + cxl_core-$(CONFIG_CXL_REGION) += region.o
+50 -1
drivers/cxl/core/core.h
··· 9 9 10 10 extern struct attribute_group cxl_base_attribute_group; 11 11 12 + #ifdef CONFIG_CXL_REGION 13 + extern struct device_attribute dev_attr_create_pmem_region; 14 + extern struct device_attribute dev_attr_delete_region; 15 + extern struct device_attribute dev_attr_region; 16 + extern const struct device_type cxl_pmem_region_type; 17 + extern const struct device_type cxl_region_type; 18 + void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled); 19 + #define CXL_REGION_ATTR(x) (&dev_attr_##x.attr) 20 + #define CXL_REGION_TYPE(x) (&cxl_region_type) 21 + #define SET_CXL_REGION_ATTR(x) (&dev_attr_##x.attr), 22 + #define CXL_PMEM_REGION_TYPE(x) (&cxl_pmem_region_type) 23 + int cxl_region_init(void); 24 + void cxl_region_exit(void); 25 + #else 26 + static inline void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled) 27 + { 28 + } 29 + static inline int cxl_region_init(void) 30 + { 31 + return 0; 32 + } 33 + static inline void cxl_region_exit(void) 34 + { 35 + } 36 + #define CXL_REGION_ATTR(x) NULL 37 + #define CXL_REGION_TYPE(x) NULL 38 + #define SET_CXL_REGION_ATTR(x) 39 + #define CXL_PMEM_REGION_TYPE(x) NULL 40 + #endif 41 + 12 42 struct cxl_send_command; 13 43 struct cxl_mem_query_commands; 14 44 int cxl_query_cmd(struct cxl_memdev *cxlmd, ··· 47 17 void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, 48 18 resource_size_t length); 49 19 20 + struct dentry *cxl_debugfs_create_dir(const char *dir); 21 + int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, 22 + enum cxl_decoder_mode mode); 23 + int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size); 24 + int cxl_dpa_free(struct cxl_endpoint_decoder *cxled); 25 + resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled); 26 + resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled); 27 + extern struct rw_semaphore cxl_dpa_rwsem; 28 + 29 + bool is_switch_decoder(struct device *dev); 30 + struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev); 31 + static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port, 32 + struct cxl_memdev *cxlmd) 33 + { 34 + if (!port) 35 + return NULL; 36 + 37 + return xa_load(&port->endpoints, (unsigned long)&cxlmd->dev); 38 + } 39 + 50 40 int cxl_memdev_init(void); 51 41 void cxl_memdev_exit(void); 52 42 void cxl_mbox_init(void); 53 - void cxl_mbox_exit(void); 54 43 55 44 #endif /* __CXL_CORE_H__ */
+638 -59
drivers/cxl/core/hdm.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 3 #include <linux/io-64-nonatomic-hi-lo.h> 4 + #include <linux/seq_file.h> 4 5 #include <linux/device.h> 5 6 #include <linux/delay.h> 6 7 ··· 16 15 * instances per CXL port and per CXL endpoint. Define common helpers 17 16 * for enumerating these registers and capabilities. 18 17 */ 18 + 19 + DECLARE_RWSEM(cxl_dpa_rwsem); 19 20 20 21 static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, 21 22 int *target_map) ··· 49 46 */ 50 47 int devm_cxl_add_passthrough_decoder(struct cxl_port *port) 51 48 { 52 - struct cxl_decoder *cxld; 53 - struct cxl_dport *dport; 49 + struct cxl_switch_decoder *cxlsd; 50 + struct cxl_dport *dport = NULL; 54 51 int single_port_map[1]; 52 + unsigned long index; 55 53 56 - cxld = cxl_switch_decoder_alloc(port, 1); 57 - if (IS_ERR(cxld)) 58 - return PTR_ERR(cxld); 54 + cxlsd = cxl_switch_decoder_alloc(port, 1); 55 + if (IS_ERR(cxlsd)) 56 + return PTR_ERR(cxlsd); 59 57 60 58 device_lock_assert(&port->dev); 61 59 62 - dport = list_first_entry(&port->dports, typeof(*dport), list); 60 + xa_for_each(&port->dports, index, dport) 61 + break; 63 62 single_port_map[0] = dport->port_id; 64 63 65 - return add_hdm_decoder(port, cxld, single_port_map); 64 + return add_hdm_decoder(port, &cxlsd->cxld, single_port_map); 66 65 } 67 66 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, CXL); 68 67 ··· 129 124 return ERR_PTR(-ENXIO); 130 125 } 131 126 127 + dev_set_drvdata(dev, cxlhdm); 128 + 132 129 return cxlhdm; 133 130 } 134 131 EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, CXL); 135 132 136 - static int to_interleave_granularity(u32 ctrl) 133 + static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth) 137 134 { 138 - int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl); 135 + unsigned long long start = r->start, end = r->end; 139 136 140 - return 256 << val; 137 + seq_printf(file, "%*s%08llx-%08llx : %s\n", depth * 2, "", start, end, 138 + r->name); 141 139 } 142 140 143 - static int to_interleave_ways(u32 ctrl) 141 + void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds) 144 142 { 145 - int val = FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl); 143 + struct resource *p1, *p2; 146 144 147 - switch (val) { 148 - case 0 ... 4: 149 - return 1 << val; 150 - case 8 ... 10: 151 - return 3 << (val - 8); 152 - default: 153 - return 0; 145 + down_read(&cxl_dpa_rwsem); 146 + for (p1 = cxlds->dpa_res.child; p1; p1 = p1->sibling) { 147 + __cxl_dpa_debug(file, p1, 0); 148 + for (p2 = p1->child; p2; p2 = p2->sibling) 149 + __cxl_dpa_debug(file, p2, 1); 154 150 } 151 + up_read(&cxl_dpa_rwsem); 152 + } 153 + EXPORT_SYMBOL_NS_GPL(cxl_dpa_debug, CXL); 154 + 155 + /* 156 + * Must be called in a context that synchronizes against this decoder's 157 + * port ->remove() callback (like an endpoint decoder sysfs attribute) 158 + */ 159 + static void __cxl_dpa_release(struct cxl_endpoint_decoder *cxled) 160 + { 161 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 162 + struct cxl_port *port = cxled_to_port(cxled); 163 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 164 + struct resource *res = cxled->dpa_res; 165 + resource_size_t skip_start; 166 + 167 + lockdep_assert_held_write(&cxl_dpa_rwsem); 168 + 169 + /* save @skip_start, before @res is released */ 170 + skip_start = res->start - cxled->skip; 171 + __release_region(&cxlds->dpa_res, res->start, resource_size(res)); 172 + if (cxled->skip) 173 + __release_region(&cxlds->dpa_res, skip_start, cxled->skip); 174 + cxled->skip = 0; 175 + cxled->dpa_res = NULL; 176 + put_device(&cxled->cxld.dev); 177 + port->hdm_end--; 178 + } 179 + 180 + static void cxl_dpa_release(void *cxled) 181 + { 182 + down_write(&cxl_dpa_rwsem); 183 + __cxl_dpa_release(cxled); 184 + up_write(&cxl_dpa_rwsem); 185 + } 186 + 187 + /* 188 + * Must be called from context that will not race port device 189 + * unregistration, like decoder sysfs attribute methods 190 + */ 191 + static void devm_cxl_dpa_release(struct cxl_endpoint_decoder *cxled) 192 + { 193 + struct cxl_port *port = cxled_to_port(cxled); 194 + 195 + lockdep_assert_held_write(&cxl_dpa_rwsem); 196 + devm_remove_action(&port->dev, cxl_dpa_release, cxled); 197 + __cxl_dpa_release(cxled); 198 + } 199 + 200 + static int __cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, 201 + resource_size_t base, resource_size_t len, 202 + resource_size_t skipped) 203 + { 204 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 205 + struct cxl_port *port = cxled_to_port(cxled); 206 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 207 + struct device *dev = &port->dev; 208 + struct resource *res; 209 + 210 + lockdep_assert_held_write(&cxl_dpa_rwsem); 211 + 212 + if (!len) 213 + goto success; 214 + 215 + if (cxled->dpa_res) { 216 + dev_dbg(dev, "decoder%d.%d: existing allocation %pr assigned\n", 217 + port->id, cxled->cxld.id, cxled->dpa_res); 218 + return -EBUSY; 219 + } 220 + 221 + if (port->hdm_end + 1 != cxled->cxld.id) { 222 + /* 223 + * Assumes alloc and commit order is always in hardware instance 224 + * order per expectations from 8.2.5.12.20 Committing Decoder 225 + * Programming that enforce decoder[m] committed before 226 + * decoder[m+1] commit start. 227 + */ 228 + dev_dbg(dev, "decoder%d.%d: expected decoder%d.%d\n", port->id, 229 + cxled->cxld.id, port->id, port->hdm_end + 1); 230 + return -EBUSY; 231 + } 232 + 233 + if (skipped) { 234 + res = __request_region(&cxlds->dpa_res, base - skipped, skipped, 235 + dev_name(&cxled->cxld.dev), 0); 236 + if (!res) { 237 + dev_dbg(dev, 238 + "decoder%d.%d: failed to reserve skipped space\n", 239 + port->id, cxled->cxld.id); 240 + return -EBUSY; 241 + } 242 + } 243 + res = __request_region(&cxlds->dpa_res, base, len, 244 + dev_name(&cxled->cxld.dev), 0); 245 + if (!res) { 246 + dev_dbg(dev, "decoder%d.%d: failed to reserve allocation\n", 247 + port->id, cxled->cxld.id); 248 + if (skipped) 249 + __release_region(&cxlds->dpa_res, base - skipped, 250 + skipped); 251 + return -EBUSY; 252 + } 253 + cxled->dpa_res = res; 254 + cxled->skip = skipped; 255 + 256 + if (resource_contains(&cxlds->pmem_res, res)) 257 + cxled->mode = CXL_DECODER_PMEM; 258 + else if (resource_contains(&cxlds->ram_res, res)) 259 + cxled->mode = CXL_DECODER_RAM; 260 + else { 261 + dev_dbg(dev, "decoder%d.%d: %pr mixed\n", port->id, 262 + cxled->cxld.id, cxled->dpa_res); 263 + cxled->mode = CXL_DECODER_MIXED; 264 + } 265 + 266 + success: 267 + port->hdm_end++; 268 + get_device(&cxled->cxld.dev); 269 + return 0; 270 + } 271 + 272 + static int devm_cxl_dpa_reserve(struct cxl_endpoint_decoder *cxled, 273 + resource_size_t base, resource_size_t len, 274 + resource_size_t skipped) 275 + { 276 + struct cxl_port *port = cxled_to_port(cxled); 277 + int rc; 278 + 279 + down_write(&cxl_dpa_rwsem); 280 + rc = __cxl_dpa_reserve(cxled, base, len, skipped); 281 + up_write(&cxl_dpa_rwsem); 282 + 283 + if (rc) 284 + return rc; 285 + 286 + return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled); 287 + } 288 + 289 + resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled) 290 + { 291 + resource_size_t size = 0; 292 + 293 + down_read(&cxl_dpa_rwsem); 294 + if (cxled->dpa_res) 295 + size = resource_size(cxled->dpa_res); 296 + up_read(&cxl_dpa_rwsem); 297 + 298 + return size; 299 + } 300 + 301 + resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled) 302 + { 303 + resource_size_t base = -1; 304 + 305 + down_read(&cxl_dpa_rwsem); 306 + if (cxled->dpa_res) 307 + base = cxled->dpa_res->start; 308 + up_read(&cxl_dpa_rwsem); 309 + 310 + return base; 311 + } 312 + 313 + int cxl_dpa_free(struct cxl_endpoint_decoder *cxled) 314 + { 315 + struct cxl_port *port = cxled_to_port(cxled); 316 + struct device *dev = &cxled->cxld.dev; 317 + int rc; 318 + 319 + down_write(&cxl_dpa_rwsem); 320 + if (!cxled->dpa_res) { 321 + rc = 0; 322 + goto out; 323 + } 324 + if (cxled->cxld.region) { 325 + dev_dbg(dev, "decoder assigned to: %s\n", 326 + dev_name(&cxled->cxld.region->dev)); 327 + rc = -EBUSY; 328 + goto out; 329 + } 330 + if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) { 331 + dev_dbg(dev, "decoder enabled\n"); 332 + rc = -EBUSY; 333 + goto out; 334 + } 335 + if (cxled->cxld.id != port->hdm_end) { 336 + dev_dbg(dev, "expected decoder%d.%d\n", port->id, 337 + port->hdm_end); 338 + rc = -EBUSY; 339 + goto out; 340 + } 341 + devm_cxl_dpa_release(cxled); 342 + rc = 0; 343 + out: 344 + up_write(&cxl_dpa_rwsem); 345 + return rc; 346 + } 347 + 348 + int cxl_dpa_set_mode(struct cxl_endpoint_decoder *cxled, 349 + enum cxl_decoder_mode mode) 350 + { 351 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 352 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 353 + struct device *dev = &cxled->cxld.dev; 354 + int rc; 355 + 356 + switch (mode) { 357 + case CXL_DECODER_RAM: 358 + case CXL_DECODER_PMEM: 359 + break; 360 + default: 361 + dev_dbg(dev, "unsupported mode: %d\n", mode); 362 + return -EINVAL; 363 + } 364 + 365 + down_write(&cxl_dpa_rwsem); 366 + if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) { 367 + rc = -EBUSY; 368 + goto out; 369 + } 370 + 371 + /* 372 + * Only allow modes that are supported by the current partition 373 + * configuration 374 + */ 375 + if (mode == CXL_DECODER_PMEM && !resource_size(&cxlds->pmem_res)) { 376 + dev_dbg(dev, "no available pmem capacity\n"); 377 + rc = -ENXIO; 378 + goto out; 379 + } 380 + if (mode == CXL_DECODER_RAM && !resource_size(&cxlds->ram_res)) { 381 + dev_dbg(dev, "no available ram capacity\n"); 382 + rc = -ENXIO; 383 + goto out; 384 + } 385 + 386 + cxled->mode = mode; 387 + rc = 0; 388 + out: 389 + up_write(&cxl_dpa_rwsem); 390 + 391 + return rc; 392 + } 393 + 394 + int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size) 395 + { 396 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 397 + resource_size_t free_ram_start, free_pmem_start; 398 + struct cxl_port *port = cxled_to_port(cxled); 399 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 400 + struct device *dev = &cxled->cxld.dev; 401 + resource_size_t start, avail, skip; 402 + struct resource *p, *last; 403 + int rc; 404 + 405 + down_write(&cxl_dpa_rwsem); 406 + if (cxled->cxld.region) { 407 + dev_dbg(dev, "decoder attached to %s\n", 408 + dev_name(&cxled->cxld.region->dev)); 409 + rc = -EBUSY; 410 + goto out; 411 + } 412 + 413 + if (cxled->cxld.flags & CXL_DECODER_F_ENABLE) { 414 + dev_dbg(dev, "decoder enabled\n"); 415 + rc = -EBUSY; 416 + goto out; 417 + } 418 + 419 + for (p = cxlds->ram_res.child, last = NULL; p; p = p->sibling) 420 + last = p; 421 + if (last) 422 + free_ram_start = last->end + 1; 423 + else 424 + free_ram_start = cxlds->ram_res.start; 425 + 426 + for (p = cxlds->pmem_res.child, last = NULL; p; p = p->sibling) 427 + last = p; 428 + if (last) 429 + free_pmem_start = last->end + 1; 430 + else 431 + free_pmem_start = cxlds->pmem_res.start; 432 + 433 + if (cxled->mode == CXL_DECODER_RAM) { 434 + start = free_ram_start; 435 + avail = cxlds->ram_res.end - start + 1; 436 + skip = 0; 437 + } else if (cxled->mode == CXL_DECODER_PMEM) { 438 + resource_size_t skip_start, skip_end; 439 + 440 + start = free_pmem_start; 441 + avail = cxlds->pmem_res.end - start + 1; 442 + skip_start = free_ram_start; 443 + 444 + /* 445 + * If some pmem is already allocated, then that allocation 446 + * already handled the skip. 447 + */ 448 + if (cxlds->pmem_res.child && 449 + skip_start == cxlds->pmem_res.child->start) 450 + skip_end = skip_start - 1; 451 + else 452 + skip_end = start - 1; 453 + skip = skip_end - skip_start + 1; 454 + } else { 455 + dev_dbg(dev, "mode not set\n"); 456 + rc = -EINVAL; 457 + goto out; 458 + } 459 + 460 + if (size > avail) { 461 + dev_dbg(dev, "%pa exceeds available %s capacity: %pa\n", &size, 462 + cxled->mode == CXL_DECODER_RAM ? "ram" : "pmem", 463 + &avail); 464 + rc = -ENOSPC; 465 + goto out; 466 + } 467 + 468 + rc = __cxl_dpa_reserve(cxled, start, size, skip); 469 + out: 470 + up_write(&cxl_dpa_rwsem); 471 + 472 + if (rc) 473 + return rc; 474 + 475 + return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled); 476 + } 477 + 478 + static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl) 479 + { 480 + u16 eig; 481 + u8 eiw; 482 + 483 + /* 484 + * Input validation ensures these warns never fire, but otherwise 485 + * suppress unititalized variable usage warnings. 486 + */ 487 + if (WARN_ONCE(ways_to_cxl(cxld->interleave_ways, &eiw), 488 + "invalid interleave_ways: %d\n", cxld->interleave_ways)) 489 + return; 490 + if (WARN_ONCE(granularity_to_cxl(cxld->interleave_granularity, &eig), 491 + "invalid interleave_granularity: %d\n", 492 + cxld->interleave_granularity)) 493 + return; 494 + 495 + u32p_replace_bits(ctrl, eig, CXL_HDM_DECODER0_CTRL_IG_MASK); 496 + u32p_replace_bits(ctrl, eiw, CXL_HDM_DECODER0_CTRL_IW_MASK); 497 + *ctrl |= CXL_HDM_DECODER0_CTRL_COMMIT; 498 + } 499 + 500 + static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl) 501 + { 502 + u32p_replace_bits(ctrl, !!(cxld->target_type == 3), 503 + CXL_HDM_DECODER0_CTRL_TYPE); 504 + } 505 + 506 + static int cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt) 507 + { 508 + struct cxl_dport **t = &cxlsd->target[0]; 509 + int ways = cxlsd->cxld.interleave_ways; 510 + 511 + if (dev_WARN_ONCE(&cxlsd->cxld.dev, 512 + ways > 8 || ways > cxlsd->nr_targets, 513 + "ways: %d overflows targets: %d\n", ways, 514 + cxlsd->nr_targets)) 515 + return -ENXIO; 516 + 517 + *tgt = FIELD_PREP(GENMASK(7, 0), t[0]->port_id); 518 + if (ways > 1) 519 + *tgt |= FIELD_PREP(GENMASK(15, 8), t[1]->port_id); 520 + if (ways > 2) 521 + *tgt |= FIELD_PREP(GENMASK(23, 16), t[2]->port_id); 522 + if (ways > 3) 523 + *tgt |= FIELD_PREP(GENMASK(31, 24), t[3]->port_id); 524 + if (ways > 4) 525 + *tgt |= FIELD_PREP(GENMASK_ULL(39, 32), t[4]->port_id); 526 + if (ways > 5) 527 + *tgt |= FIELD_PREP(GENMASK_ULL(47, 40), t[5]->port_id); 528 + if (ways > 6) 529 + *tgt |= FIELD_PREP(GENMASK_ULL(55, 48), t[6]->port_id); 530 + if (ways > 7) 531 + *tgt |= FIELD_PREP(GENMASK_ULL(63, 56), t[7]->port_id); 532 + 533 + return 0; 534 + } 535 + 536 + /* 537 + * Per CXL 2.0 8.2.5.12.20 Committing Decoder Programming, hardware must set 538 + * committed or error within 10ms, but just be generous with 20ms to account for 539 + * clock skew and other marginal behavior 540 + */ 541 + #define COMMIT_TIMEOUT_MS 20 542 + static int cxld_await_commit(void __iomem *hdm, int id) 543 + { 544 + u32 ctrl; 545 + int i; 546 + 547 + for (i = 0; i < COMMIT_TIMEOUT_MS; i++) { 548 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 549 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMIT_ERROR, ctrl)) { 550 + ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT; 551 + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 552 + return -EIO; 553 + } 554 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) 555 + return 0; 556 + fsleep(1000); 557 + } 558 + 559 + return -ETIMEDOUT; 560 + } 561 + 562 + static int cxl_decoder_commit(struct cxl_decoder *cxld) 563 + { 564 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 565 + struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 566 + void __iomem *hdm = cxlhdm->regs.hdm_decoder; 567 + int id = cxld->id, rc; 568 + u64 base, size; 569 + u32 ctrl; 570 + 571 + if (cxld->flags & CXL_DECODER_F_ENABLE) 572 + return 0; 573 + 574 + if (port->commit_end + 1 != id) { 575 + dev_dbg(&port->dev, 576 + "%s: out of order commit, expected decoder%d.%d\n", 577 + dev_name(&cxld->dev), port->id, port->commit_end + 1); 578 + return -EBUSY; 579 + } 580 + 581 + down_read(&cxl_dpa_rwsem); 582 + /* common decoder settings */ 583 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id)); 584 + cxld_set_interleave(cxld, &ctrl); 585 + cxld_set_type(cxld, &ctrl); 586 + base = cxld->hpa_range.start; 587 + size = range_len(&cxld->hpa_range); 588 + 589 + writel(upper_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id)); 590 + writel(lower_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id)); 591 + writel(upper_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id)); 592 + writel(lower_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id)); 593 + 594 + if (is_switch_decoder(&cxld->dev)) { 595 + struct cxl_switch_decoder *cxlsd = 596 + to_cxl_switch_decoder(&cxld->dev); 597 + void __iomem *tl_hi = hdm + CXL_HDM_DECODER0_TL_HIGH(id); 598 + void __iomem *tl_lo = hdm + CXL_HDM_DECODER0_TL_LOW(id); 599 + u64 targets; 600 + 601 + rc = cxlsd_set_targets(cxlsd, &targets); 602 + if (rc) { 603 + dev_dbg(&port->dev, "%s: target configuration error\n", 604 + dev_name(&cxld->dev)); 605 + goto err; 606 + } 607 + 608 + writel(upper_32_bits(targets), tl_hi); 609 + writel(lower_32_bits(targets), tl_lo); 610 + } else { 611 + struct cxl_endpoint_decoder *cxled = 612 + to_cxl_endpoint_decoder(&cxld->dev); 613 + void __iomem *sk_hi = hdm + CXL_HDM_DECODER0_SKIP_HIGH(id); 614 + void __iomem *sk_lo = hdm + CXL_HDM_DECODER0_SKIP_LOW(id); 615 + 616 + writel(upper_32_bits(cxled->skip), sk_hi); 617 + writel(lower_32_bits(cxled->skip), sk_lo); 618 + } 619 + 620 + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 621 + up_read(&cxl_dpa_rwsem); 622 + 623 + port->commit_end++; 624 + rc = cxld_await_commit(hdm, cxld->id); 625 + err: 626 + if (rc) { 627 + dev_dbg(&port->dev, "%s: error %d committing decoder\n", 628 + dev_name(&cxld->dev), rc); 629 + cxld->reset(cxld); 630 + return rc; 631 + } 632 + cxld->flags |= CXL_DECODER_F_ENABLE; 633 + 634 + return 0; 635 + } 636 + 637 + static int cxl_decoder_reset(struct cxl_decoder *cxld) 638 + { 639 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 640 + struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev); 641 + void __iomem *hdm = cxlhdm->regs.hdm_decoder; 642 + int id = cxld->id; 643 + u32 ctrl; 644 + 645 + if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0) 646 + return 0; 647 + 648 + if (port->commit_end != id) { 649 + dev_dbg(&port->dev, 650 + "%s: out of order reset, expected decoder%d.%d\n", 651 + dev_name(&cxld->dev), port->id, port->commit_end); 652 + return -EBUSY; 653 + } 654 + 655 + down_read(&cxl_dpa_rwsem); 656 + ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 657 + ctrl &= ~CXL_HDM_DECODER0_CTRL_COMMIT; 658 + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id)); 659 + 660 + writel(0, hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id)); 661 + writel(0, hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id)); 662 + writel(0, hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id)); 663 + writel(0, hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id)); 664 + up_read(&cxl_dpa_rwsem); 665 + 666 + port->commit_end--; 667 + cxld->flags &= ~CXL_DECODER_F_ENABLE; 668 + 669 + return 0; 155 670 } 156 671 157 672 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, 158 - int *target_map, void __iomem *hdm, int which) 673 + int *target_map, void __iomem *hdm, int which, 674 + u64 *dpa_base) 159 675 { 160 - u64 size, base; 676 + struct cxl_endpoint_decoder *cxled = NULL; 677 + u64 size, base, skip, dpa_size; 678 + bool committed; 679 + u32 remainder; 680 + int i, rc; 161 681 u32 ctrl; 162 - int i; 163 682 union { 164 683 u64 value; 165 684 unsigned char target_id[8]; 166 685 } target_list; 167 686 687 + if (is_endpoint_decoder(&cxld->dev)) 688 + cxled = to_cxl_endpoint_decoder(&cxld->dev); 689 + 168 690 ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which)); 169 691 base = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(which)); 170 692 size = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(which)); 693 + committed = !!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED); 694 + cxld->commit = cxl_decoder_commit; 695 + cxld->reset = cxl_decoder_reset; 171 696 172 - if (!(ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED)) 697 + if (!committed) 173 698 size = 0; 174 699 if (base == U64_MAX || size == U64_MAX) { 175 700 dev_warn(&port->dev, "decoder%d.%d: Invalid resource range\n", ··· 707 172 return -ENXIO; 708 173 } 709 174 710 - cxld->decoder_range = (struct range) { 175 + cxld->hpa_range = (struct range) { 711 176 .start = base, 712 177 .end = base + size - 1, 713 178 }; 714 179 715 - /* switch decoders are always enabled if committed */ 716 - if (ctrl & CXL_HDM_DECODER0_CTRL_COMMITTED) { 180 + /* decoders are enabled if committed */ 181 + if (committed) { 717 182 cxld->flags |= CXL_DECODER_F_ENABLE; 718 183 if (ctrl & CXL_HDM_DECODER0_CTRL_LOCK) 719 184 cxld->flags |= CXL_DECODER_F_LOCK; 185 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl)) 186 + cxld->target_type = CXL_DECODER_EXPANDER; 187 + else 188 + cxld->target_type = CXL_DECODER_ACCELERATOR; 189 + if (cxld->id != port->commit_end + 1) { 190 + dev_warn(&port->dev, 191 + "decoder%d.%d: Committed out of order\n", 192 + port->id, cxld->id); 193 + return -ENXIO; 194 + } 195 + port->commit_end = cxld->id; 196 + } else { 197 + /* unless / until type-2 drivers arrive, assume type-3 */ 198 + if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl) == 0) { 199 + ctrl |= CXL_HDM_DECODER0_CTRL_TYPE; 200 + writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(which)); 201 + } 202 + cxld->target_type = CXL_DECODER_EXPANDER; 720 203 } 721 - cxld->interleave_ways = to_interleave_ways(ctrl); 722 - if (!cxld->interleave_ways) { 204 + rc = cxl_to_ways(FIELD_GET(CXL_HDM_DECODER0_CTRL_IW_MASK, ctrl), 205 + &cxld->interleave_ways); 206 + if (rc) { 723 207 dev_warn(&port->dev, 724 208 "decoder%d.%d: Invalid interleave ways (ctrl: %#x)\n", 725 209 port->id, cxld->id, ctrl); 726 - return -ENXIO; 210 + return rc; 727 211 } 728 - cxld->interleave_granularity = to_interleave_granularity(ctrl); 212 + rc = cxl_to_granularity(FIELD_GET(CXL_HDM_DECODER0_CTRL_IG_MASK, ctrl), 213 + &cxld->interleave_granularity); 214 + if (rc) 215 + return rc; 729 216 730 - if (FIELD_GET(CXL_HDM_DECODER0_CTRL_TYPE, ctrl)) 731 - cxld->target_type = CXL_DECODER_EXPANDER; 732 - else 733 - cxld->target_type = CXL_DECODER_ACCELERATOR; 217 + if (!cxled) { 218 + target_list.value = 219 + ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); 220 + for (i = 0; i < cxld->interleave_ways; i++) 221 + target_map[i] = target_list.target_id[i]; 734 222 735 - if (is_endpoint_decoder(&cxld->dev)) 223 + return 0; 224 + } 225 + 226 + if (!committed) 736 227 return 0; 737 228 738 - target_list.value = 739 - ioread64_hi_lo(hdm + CXL_HDM_DECODER0_TL_LOW(which)); 740 - for (i = 0; i < cxld->interleave_ways; i++) 741 - target_map[i] = target_list.target_id[i]; 742 - 229 + dpa_size = div_u64_rem(size, cxld->interleave_ways, &remainder); 230 + if (remainder) { 231 + dev_err(&port->dev, 232 + "decoder%d.%d: invalid committed configuration size: %#llx ways: %d\n", 233 + port->id, cxld->id, size, cxld->interleave_ways); 234 + return -ENXIO; 235 + } 236 + skip = ioread64_hi_lo(hdm + CXL_HDM_DECODER0_SKIP_LOW(which)); 237 + rc = devm_cxl_dpa_reserve(cxled, *dpa_base + skip, dpa_size, skip); 238 + if (rc) { 239 + dev_err(&port->dev, 240 + "decoder%d.%d: Failed to reserve DPA range %#llx - %#llx\n (%d)", 241 + port->id, cxld->id, *dpa_base, 242 + *dpa_base + dpa_size + skip - 1, rc); 243 + return rc; 244 + } 245 + *dpa_base += dpa_size + skip; 743 246 return 0; 744 247 } 745 248 ··· 789 216 { 790 217 void __iomem *hdm = cxlhdm->regs.hdm_decoder; 791 218 struct cxl_port *port = cxlhdm->port; 792 - int i, committed, failed; 219 + int i, committed; 220 + u64 dpa_base = 0; 793 221 u32 ctrl; 794 222 795 223 /* ··· 810 236 if (committed != cxlhdm->decoder_count) 811 237 msleep(20); 812 238 813 - for (i = 0, failed = 0; i < cxlhdm->decoder_count; i++) { 239 + for (i = 0; i < cxlhdm->decoder_count; i++) { 814 240 int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 }; 815 241 int rc, target_count = cxlhdm->target_count; 816 242 struct cxl_decoder *cxld; 817 243 818 - if (is_cxl_endpoint(port)) 819 - cxld = cxl_endpoint_decoder_alloc(port); 820 - else 821 - cxld = cxl_switch_decoder_alloc(port, target_count); 822 - if (IS_ERR(cxld)) { 823 - dev_warn(&port->dev, 824 - "Failed to allocate the decoder\n"); 825 - return PTR_ERR(cxld); 244 + if (is_cxl_endpoint(port)) { 245 + struct cxl_endpoint_decoder *cxled; 246 + 247 + cxled = cxl_endpoint_decoder_alloc(port); 248 + if (IS_ERR(cxled)) { 249 + dev_warn(&port->dev, 250 + "Failed to allocate the decoder\n"); 251 + return PTR_ERR(cxled); 252 + } 253 + cxld = &cxled->cxld; 254 + } else { 255 + struct cxl_switch_decoder *cxlsd; 256 + 257 + cxlsd = cxl_switch_decoder_alloc(port, target_count); 258 + if (IS_ERR(cxlsd)) { 259 + dev_warn(&port->dev, 260 + "Failed to allocate the decoder\n"); 261 + return PTR_ERR(cxlsd); 262 + } 263 + cxld = &cxlsd->cxld; 826 264 } 827 265 828 - rc = init_hdm_decoder(port, cxld, target_map, 829 - cxlhdm->regs.hdm_decoder, i); 266 + rc = init_hdm_decoder(port, cxld, target_map, hdm, i, &dpa_base); 830 267 if (rc) { 831 268 put_device(&cxld->dev); 832 - failed++; 833 - continue; 269 + return rc; 834 270 } 835 271 rc = add_hdm_decoder(port, cxld, target_map); 836 272 if (rc) { ··· 848 264 "Failed to add decoder to port\n"); 849 265 return rc; 850 266 } 851 - } 852 - 853 - if (failed == cxlhdm->decoder_count) { 854 - dev_err(&port->dev, "No valid decoders found\n"); 855 - return -ENXIO; 856 267 } 857 268 858 269 return 0;
+48 -49
drivers/cxl/core/mbox.c
··· 718 718 */ 719 719 static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds) 720 720 { 721 - struct cxl_mbox_get_partition_info { 722 - __le64 active_volatile_cap; 723 - __le64 active_persistent_cap; 724 - __le64 next_volatile_cap; 725 - __le64 next_persistent_cap; 726 - } __packed pi; 721 + struct cxl_mbox_get_partition_info pi; 727 722 int rc; 728 723 729 724 rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0, ··· 768 773 cxlds->partition_align_bytes = 769 774 le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER; 770 775 771 - dev_dbg(cxlds->dev, 772 - "Identify Memory Device\n" 773 - " total_bytes = %#llx\n" 774 - " volatile_only_bytes = %#llx\n" 775 - " persistent_only_bytes = %#llx\n" 776 - " partition_align_bytes = %#llx\n", 777 - cxlds->total_bytes, cxlds->volatile_only_bytes, 778 - cxlds->persistent_only_bytes, cxlds->partition_align_bytes); 779 - 780 776 cxlds->lsa_size = le32_to_cpu(id.lsa_size); 781 777 memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision)); 782 778 ··· 775 789 } 776 790 EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL); 777 791 778 - int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) 792 + static int add_dpa_res(struct device *dev, struct resource *parent, 793 + struct resource *res, resource_size_t start, 794 + resource_size_t size, const char *type) 779 795 { 780 796 int rc; 781 797 782 - if (cxlds->partition_align_bytes == 0) { 783 - cxlds->ram_range.start = 0; 784 - cxlds->ram_range.end = cxlds->volatile_only_bytes - 1; 785 - cxlds->pmem_range.start = cxlds->volatile_only_bytes; 786 - cxlds->pmem_range.end = cxlds->volatile_only_bytes + 787 - cxlds->persistent_only_bytes - 1; 798 + res->name = type; 799 + res->start = start; 800 + res->end = start + size - 1; 801 + res->flags = IORESOURCE_MEM; 802 + if (resource_size(res) == 0) { 803 + dev_dbg(dev, "DPA(%s): no capacity\n", res->name); 788 804 return 0; 805 + } 806 + rc = request_resource(parent, res); 807 + if (rc) { 808 + dev_err(dev, "DPA(%s): failed to track %pr (%d)\n", res->name, 809 + res, rc); 810 + return rc; 811 + } 812 + 813 + dev_dbg(dev, "DPA(%s): %pr\n", res->name, res); 814 + 815 + return 0; 816 + } 817 + 818 + int cxl_mem_create_range_info(struct cxl_dev_state *cxlds) 819 + { 820 + struct device *dev = cxlds->dev; 821 + int rc; 822 + 823 + cxlds->dpa_res = 824 + (struct resource)DEFINE_RES_MEM(0, cxlds->total_bytes); 825 + 826 + if (cxlds->partition_align_bytes == 0) { 827 + rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0, 828 + cxlds->volatile_only_bytes, "ram"); 829 + if (rc) 830 + return rc; 831 + return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res, 832 + cxlds->volatile_only_bytes, 833 + cxlds->persistent_only_bytes, "pmem"); 789 834 } 790 835 791 836 rc = cxl_mem_get_partition_info(cxlds); 792 837 if (rc) { 793 - dev_err(cxlds->dev, "Failed to query partition information\n"); 838 + dev_err(dev, "Failed to query partition information\n"); 794 839 return rc; 795 840 } 796 841 797 - dev_dbg(cxlds->dev, 798 - "Get Partition Info\n" 799 - " active_volatile_bytes = %#llx\n" 800 - " active_persistent_bytes = %#llx\n" 801 - " next_volatile_bytes = %#llx\n" 802 - " next_persistent_bytes = %#llx\n", 803 - cxlds->active_volatile_bytes, cxlds->active_persistent_bytes, 804 - cxlds->next_volatile_bytes, cxlds->next_persistent_bytes); 805 - 806 - cxlds->ram_range.start = 0; 807 - cxlds->ram_range.end = cxlds->active_volatile_bytes - 1; 808 - 809 - cxlds->pmem_range.start = cxlds->active_volatile_bytes; 810 - cxlds->pmem_range.end = 811 - cxlds->active_volatile_bytes + cxlds->active_persistent_bytes - 1; 812 - 813 - return 0; 842 + rc = add_dpa_res(dev, &cxlds->dpa_res, &cxlds->ram_res, 0, 843 + cxlds->active_volatile_bytes, "ram"); 844 + if (rc) 845 + return rc; 846 + return add_dpa_res(dev, &cxlds->dpa_res, &cxlds->pmem_res, 847 + cxlds->active_volatile_bytes, 848 + cxlds->active_persistent_bytes, "pmem"); 814 849 } 815 850 EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL); 816 851 ··· 852 845 } 853 846 EXPORT_SYMBOL_NS_GPL(cxl_dev_state_create, CXL); 854 847 855 - static struct dentry *cxl_debugfs; 856 - 857 848 void __init cxl_mbox_init(void) 858 849 { 859 850 struct dentry *mbox_debugfs; 860 851 861 - cxl_debugfs = debugfs_create_dir("cxl", NULL); 862 - mbox_debugfs = debugfs_create_dir("mbox", cxl_debugfs); 852 + mbox_debugfs = cxl_debugfs_create_dir("mbox"); 863 853 debugfs_create_bool("raw_allow_all", 0600, mbox_debugfs, 864 854 &cxl_raw_allow_all); 865 - } 866 - 867 - void cxl_mbox_exit(void) 868 - { 869 - debugfs_remove_recursive(cxl_debugfs); 870 855 }
+2 -2
drivers/cxl/core/memdev.c
··· 68 68 { 69 69 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 70 70 struct cxl_dev_state *cxlds = cxlmd->cxlds; 71 - unsigned long long len = range_len(&cxlds->ram_range); 71 + unsigned long long len = resource_size(&cxlds->ram_res); 72 72 73 73 return sysfs_emit(buf, "%#llx\n", len); 74 74 } ··· 81 81 { 82 82 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 83 83 struct cxl_dev_state *cxlds = cxlmd->cxlds; 84 - unsigned long long len = range_len(&cxlds->pmem_range); 84 + unsigned long long len = resource_size(&cxlds->pmem_res); 85 85 86 86 return sysfs_emit(buf, "%#llx\n", len); 87 87 }
+174 -7
drivers/cxl/core/pci.c
··· 4 4 #include <linux/device.h> 5 5 #include <linux/delay.h> 6 6 #include <linux/pci.h> 7 + #include <linux/pci-doe.h> 7 8 #include <cxlpci.h> 8 9 #include <cxlmem.h> 9 10 #include <cxl.h> ··· 226 225 { 227 226 struct range *dev_range = arg; 228 227 struct cxl_decoder *cxld; 229 - struct range root_range; 230 228 231 229 if (!is_root_decoder(dev)) 232 230 return 0; ··· 237 237 if (!(cxld->flags & CXL_DECODER_F_RAM)) 238 238 return 0; 239 239 240 - root_range = (struct range) { 241 - .start = cxld->platform_res.start, 242 - .end = cxld->platform_res.end, 243 - }; 244 - 245 - return range_contains(&root_range, dev_range); 240 + return range_contains(&cxld->hpa_range, dev_range); 246 241 } 247 242 248 243 static void disable_hdm(void *_cxlhdm) ··· 453 458 return 0; 454 459 } 455 460 EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, CXL); 461 + 462 + #define CXL_DOE_TABLE_ACCESS_REQ_CODE 0x000000ff 463 + #define CXL_DOE_TABLE_ACCESS_REQ_CODE_READ 0 464 + #define CXL_DOE_TABLE_ACCESS_TABLE_TYPE 0x0000ff00 465 + #define CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA 0 466 + #define CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE 0xffff0000 467 + #define CXL_DOE_TABLE_ACCESS_LAST_ENTRY 0xffff 468 + #define CXL_DOE_PROTOCOL_TABLE_ACCESS 2 469 + 470 + static struct pci_doe_mb *find_cdat_doe(struct device *uport) 471 + { 472 + struct cxl_memdev *cxlmd; 473 + struct cxl_dev_state *cxlds; 474 + unsigned long index; 475 + void *entry; 476 + 477 + cxlmd = to_cxl_memdev(uport); 478 + cxlds = cxlmd->cxlds; 479 + 480 + xa_for_each(&cxlds->doe_mbs, index, entry) { 481 + struct pci_doe_mb *cur = entry; 482 + 483 + if (pci_doe_supports_prot(cur, PCI_DVSEC_VENDOR_ID_CXL, 484 + CXL_DOE_PROTOCOL_TABLE_ACCESS)) 485 + return cur; 486 + } 487 + 488 + return NULL; 489 + } 490 + 491 + #define CDAT_DOE_REQ(entry_handle) \ 492 + (FIELD_PREP(CXL_DOE_TABLE_ACCESS_REQ_CODE, \ 493 + CXL_DOE_TABLE_ACCESS_REQ_CODE_READ) | \ 494 + FIELD_PREP(CXL_DOE_TABLE_ACCESS_TABLE_TYPE, \ 495 + CXL_DOE_TABLE_ACCESS_TABLE_TYPE_CDATA) | \ 496 + FIELD_PREP(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, (entry_handle))) 497 + 498 + static void cxl_doe_task_complete(struct pci_doe_task *task) 499 + { 500 + complete(task->private); 501 + } 502 + 503 + struct cdat_doe_task { 504 + u32 request_pl; 505 + u32 response_pl[32]; 506 + struct completion c; 507 + struct pci_doe_task task; 508 + }; 509 + 510 + #define DECLARE_CDAT_DOE_TASK(req, cdt) \ 511 + struct cdat_doe_task cdt = { \ 512 + .c = COMPLETION_INITIALIZER_ONSTACK(cdt.c), \ 513 + .request_pl = req, \ 514 + .task = { \ 515 + .prot.vid = PCI_DVSEC_VENDOR_ID_CXL, \ 516 + .prot.type = CXL_DOE_PROTOCOL_TABLE_ACCESS, \ 517 + .request_pl = &cdt.request_pl, \ 518 + .request_pl_sz = sizeof(cdt.request_pl), \ 519 + .response_pl = cdt.response_pl, \ 520 + .response_pl_sz = sizeof(cdt.response_pl), \ 521 + .complete = cxl_doe_task_complete, \ 522 + .private = &cdt.c, \ 523 + } \ 524 + } 525 + 526 + static int cxl_cdat_get_length(struct device *dev, 527 + struct pci_doe_mb *cdat_doe, 528 + size_t *length) 529 + { 530 + DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(0), t); 531 + int rc; 532 + 533 + rc = pci_doe_submit_task(cdat_doe, &t.task); 534 + if (rc < 0) { 535 + dev_err(dev, "DOE submit failed: %d", rc); 536 + return rc; 537 + } 538 + wait_for_completion(&t.c); 539 + if (t.task.rv < sizeof(u32)) 540 + return -EIO; 541 + 542 + *length = t.response_pl[1]; 543 + dev_dbg(dev, "CDAT length %zu\n", *length); 544 + 545 + return 0; 546 + } 547 + 548 + static int cxl_cdat_read_table(struct device *dev, 549 + struct pci_doe_mb *cdat_doe, 550 + struct cxl_cdat *cdat) 551 + { 552 + size_t length = cdat->length; 553 + u32 *data = cdat->table; 554 + int entry_handle = 0; 555 + 556 + do { 557 + DECLARE_CDAT_DOE_TASK(CDAT_DOE_REQ(entry_handle), t); 558 + size_t entry_dw; 559 + u32 *entry; 560 + int rc; 561 + 562 + rc = pci_doe_submit_task(cdat_doe, &t.task); 563 + if (rc < 0) { 564 + dev_err(dev, "DOE submit failed: %d", rc); 565 + return rc; 566 + } 567 + wait_for_completion(&t.c); 568 + /* 1 DW header + 1 DW data min */ 569 + if (t.task.rv < (2 * sizeof(u32))) 570 + return -EIO; 571 + 572 + /* Get the CXL table access header entry handle */ 573 + entry_handle = FIELD_GET(CXL_DOE_TABLE_ACCESS_ENTRY_HANDLE, 574 + t.response_pl[0]); 575 + entry = t.response_pl + 1; 576 + entry_dw = t.task.rv / sizeof(u32); 577 + /* Skip Header */ 578 + entry_dw -= 1; 579 + entry_dw = min(length / sizeof(u32), entry_dw); 580 + /* Prevent length < 1 DW from causing a buffer overflow */ 581 + if (entry_dw) { 582 + memcpy(data, entry, entry_dw * sizeof(u32)); 583 + length -= entry_dw * sizeof(u32); 584 + data += entry_dw; 585 + } 586 + } while (entry_handle != CXL_DOE_TABLE_ACCESS_LAST_ENTRY); 587 + 588 + return 0; 589 + } 590 + 591 + /** 592 + * read_cdat_data - Read the CDAT data on this port 593 + * @port: Port to read data from 594 + * 595 + * This call will sleep waiting for responses from the DOE mailbox. 596 + */ 597 + void read_cdat_data(struct cxl_port *port) 598 + { 599 + struct pci_doe_mb *cdat_doe; 600 + struct device *dev = &port->dev; 601 + struct device *uport = port->uport; 602 + size_t cdat_length; 603 + int rc; 604 + 605 + cdat_doe = find_cdat_doe(uport); 606 + if (!cdat_doe) { 607 + dev_dbg(dev, "No CDAT mailbox\n"); 608 + return; 609 + } 610 + 611 + port->cdat_available = true; 612 + 613 + if (cxl_cdat_get_length(dev, cdat_doe, &cdat_length)) { 614 + dev_dbg(dev, "No CDAT length\n"); 615 + return; 616 + } 617 + 618 + port->cdat.table = devm_kzalloc(dev, cdat_length, GFP_KERNEL); 619 + if (!port->cdat.table) 620 + return; 621 + 622 + port->cdat.length = cdat_length; 623 + rc = cxl_cdat_read_table(dev, cdat_doe, &port->cdat); 624 + if (rc) { 625 + /* Don't leave table data allocated on error */ 626 + devm_kfree(dev, port->cdat.table); 627 + port->cdat.table = NULL; 628 + port->cdat.length = 0; 629 + dev_err(dev, "CDAT data read error\n"); 630 + } 631 + } 632 + EXPORT_SYMBOL_NS_GPL(read_cdat_data, CXL);
+2 -2
drivers/cxl/core/pmem.c
··· 62 62 return is_cxl_nvdimm_bridge(dev); 63 63 } 64 64 65 - struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd) 65 + struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *start) 66 66 { 67 - struct cxl_port *port = find_cxl_root(&cxl_nvd->dev); 67 + struct cxl_port *port = find_cxl_root(start); 68 68 struct device *dev; 69 69 70 70 if (!port)
+536 -202
drivers/cxl/core/port.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ 3 3 #include <linux/io-64-nonatomic-lo-hi.h> 4 + #include <linux/memregion.h> 4 5 #include <linux/workqueue.h> 6 + #include <linux/debugfs.h> 5 7 #include <linux/device.h> 6 8 #include <linux/module.h> 7 9 #include <linux/pci.h> ··· 44 42 return CXL_DEVICE_NVDIMM_BRIDGE; 45 43 if (dev->type == &cxl_nvdimm_type) 46 44 return CXL_DEVICE_NVDIMM; 45 + if (dev->type == CXL_PMEM_REGION_TYPE()) 46 + return CXL_DEVICE_PMEM_REGION; 47 47 if (is_cxl_port(dev)) { 48 48 if (is_cxl_root(to_cxl_port(dev))) 49 49 return CXL_DEVICE_ROOT; ··· 53 49 } 54 50 if (is_cxl_memdev(dev)) 55 51 return CXL_DEVICE_MEMORY_EXPANDER; 52 + if (dev->type == CXL_REGION_TYPE()) 53 + return CXL_DEVICE_REGION; 56 54 return 0; 57 55 } 58 56 ··· 79 73 char *buf) 80 74 { 81 75 struct cxl_decoder *cxld = to_cxl_decoder(dev); 82 - u64 start; 83 76 84 - if (is_root_decoder(dev)) 85 - start = cxld->platform_res.start; 86 - else 87 - start = cxld->decoder_range.start; 88 - 89 - return sysfs_emit(buf, "%#llx\n", start); 77 + return sysfs_emit(buf, "%#llx\n", cxld->hpa_range.start); 90 78 } 91 79 static DEVICE_ATTR_ADMIN_RO(start); 92 80 ··· 88 88 char *buf) 89 89 { 90 90 struct cxl_decoder *cxld = to_cxl_decoder(dev); 91 - u64 size; 92 91 93 - if (is_root_decoder(dev)) 94 - size = resource_size(&cxld->platform_res); 95 - else 96 - size = range_len(&cxld->decoder_range); 97 - 98 - return sysfs_emit(buf, "%#llx\n", size); 92 + return sysfs_emit(buf, "%#llx\n", range_len(&cxld->hpa_range)); 99 93 } 100 94 static DEVICE_ATTR_RO(size); 101 95 ··· 125 131 } 126 132 static DEVICE_ATTR_RO(target_type); 127 133 128 - static ssize_t emit_target_list(struct cxl_decoder *cxld, char *buf) 134 + static ssize_t emit_target_list(struct cxl_switch_decoder *cxlsd, char *buf) 129 135 { 136 + struct cxl_decoder *cxld = &cxlsd->cxld; 130 137 ssize_t offset = 0; 131 138 int i, rc = 0; 132 139 133 140 for (i = 0; i < cxld->interleave_ways; i++) { 134 - struct cxl_dport *dport = cxld->target[i]; 141 + struct cxl_dport *dport = cxlsd->target[i]; 135 142 struct cxl_dport *next = NULL; 136 143 137 144 if (!dport) 138 145 break; 139 146 140 147 if (i + 1 < cxld->interleave_ways) 141 - next = cxld->target[i + 1]; 148 + next = cxlsd->target[i + 1]; 142 149 rc = sysfs_emit_at(buf, offset, "%d%s", dport->port_id, 143 150 next ? "," : ""); 144 151 if (rc < 0) ··· 153 158 static ssize_t target_list_show(struct device *dev, 154 159 struct device_attribute *attr, char *buf) 155 160 { 156 - struct cxl_decoder *cxld = to_cxl_decoder(dev); 161 + struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); 157 162 ssize_t offset; 158 163 unsigned int seq; 159 164 int rc; 160 165 161 166 do { 162 - seq = read_seqbegin(&cxld->target_lock); 163 - rc = emit_target_list(cxld, buf); 164 - } while (read_seqretry(&cxld->target_lock, seq)); 167 + seq = read_seqbegin(&cxlsd->target_lock); 168 + rc = emit_target_list(cxlsd, buf); 169 + } while (read_seqretry(&cxlsd->target_lock, seq)); 165 170 166 171 if (rc < 0) 167 172 return rc; ··· 175 180 } 176 181 static DEVICE_ATTR_RO(target_list); 177 182 183 + static ssize_t mode_show(struct device *dev, struct device_attribute *attr, 184 + char *buf) 185 + { 186 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 187 + 188 + switch (cxled->mode) { 189 + case CXL_DECODER_RAM: 190 + return sysfs_emit(buf, "ram\n"); 191 + case CXL_DECODER_PMEM: 192 + return sysfs_emit(buf, "pmem\n"); 193 + case CXL_DECODER_NONE: 194 + return sysfs_emit(buf, "none\n"); 195 + case CXL_DECODER_MIXED: 196 + default: 197 + return sysfs_emit(buf, "mixed\n"); 198 + } 199 + } 200 + 201 + static ssize_t mode_store(struct device *dev, struct device_attribute *attr, 202 + const char *buf, size_t len) 203 + { 204 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 205 + enum cxl_decoder_mode mode; 206 + ssize_t rc; 207 + 208 + if (sysfs_streq(buf, "pmem")) 209 + mode = CXL_DECODER_PMEM; 210 + else if (sysfs_streq(buf, "ram")) 211 + mode = CXL_DECODER_RAM; 212 + else 213 + return -EINVAL; 214 + 215 + rc = cxl_dpa_set_mode(cxled, mode); 216 + if (rc) 217 + return rc; 218 + 219 + return len; 220 + } 221 + static DEVICE_ATTR_RW(mode); 222 + 223 + static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *attr, 224 + char *buf) 225 + { 226 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 227 + u64 base = cxl_dpa_resource_start(cxled); 228 + 229 + return sysfs_emit(buf, "%#llx\n", base); 230 + } 231 + static DEVICE_ATTR_RO(dpa_resource); 232 + 233 + static ssize_t dpa_size_show(struct device *dev, struct device_attribute *attr, 234 + char *buf) 235 + { 236 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 237 + resource_size_t size = cxl_dpa_size(cxled); 238 + 239 + return sysfs_emit(buf, "%pa\n", &size); 240 + } 241 + 242 + static ssize_t dpa_size_store(struct device *dev, struct device_attribute *attr, 243 + const char *buf, size_t len) 244 + { 245 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 246 + unsigned long long size; 247 + ssize_t rc; 248 + 249 + rc = kstrtoull(buf, 0, &size); 250 + if (rc) 251 + return rc; 252 + 253 + if (!IS_ALIGNED(size, SZ_256M)) 254 + return -EINVAL; 255 + 256 + rc = cxl_dpa_free(cxled); 257 + if (rc) 258 + return rc; 259 + 260 + if (size == 0) 261 + return len; 262 + 263 + rc = cxl_dpa_alloc(cxled, size); 264 + if (rc) 265 + return rc; 266 + 267 + return len; 268 + } 269 + static DEVICE_ATTR_RW(dpa_size); 270 + 271 + static ssize_t interleave_granularity_show(struct device *dev, 272 + struct device_attribute *attr, 273 + char *buf) 274 + { 275 + struct cxl_decoder *cxld = to_cxl_decoder(dev); 276 + 277 + return sysfs_emit(buf, "%d\n", cxld->interleave_granularity); 278 + } 279 + 280 + static DEVICE_ATTR_RO(interleave_granularity); 281 + 282 + static ssize_t interleave_ways_show(struct device *dev, 283 + struct device_attribute *attr, char *buf) 284 + { 285 + struct cxl_decoder *cxld = to_cxl_decoder(dev); 286 + 287 + return sysfs_emit(buf, "%d\n", cxld->interleave_ways); 288 + } 289 + 290 + static DEVICE_ATTR_RO(interleave_ways); 291 + 178 292 static struct attribute *cxl_decoder_base_attrs[] = { 179 293 &dev_attr_start.attr, 180 294 &dev_attr_size.attr, 181 295 &dev_attr_locked.attr, 296 + &dev_attr_interleave_granularity.attr, 297 + &dev_attr_interleave_ways.attr, 182 298 NULL, 183 299 }; 184 300 ··· 303 197 &dev_attr_cap_type2.attr, 304 198 &dev_attr_cap_type3.attr, 305 199 &dev_attr_target_list.attr, 200 + SET_CXL_REGION_ATTR(create_pmem_region) 201 + SET_CXL_REGION_ATTR(delete_region) 306 202 NULL, 307 203 }; 308 204 205 + static bool can_create_pmem(struct cxl_root_decoder *cxlrd) 206 + { 207 + unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM; 208 + 209 + return (cxlrd->cxlsd.cxld.flags & flags) == flags; 210 + } 211 + 212 + static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n) 213 + { 214 + struct device *dev = kobj_to_dev(kobj); 215 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 216 + 217 + if (a == CXL_REGION_ATTR(create_pmem_region) && !can_create_pmem(cxlrd)) 218 + return 0; 219 + 220 + if (a == CXL_REGION_ATTR(delete_region) && !can_create_pmem(cxlrd)) 221 + return 0; 222 + 223 + return a->mode; 224 + } 225 + 309 226 static struct attribute_group cxl_decoder_root_attribute_group = { 310 227 .attrs = cxl_decoder_root_attrs, 228 + .is_visible = cxl_root_decoder_visible, 311 229 }; 312 230 313 231 static const struct attribute_group *cxl_decoder_root_attribute_groups[] = { ··· 344 214 static struct attribute *cxl_decoder_switch_attrs[] = { 345 215 &dev_attr_target_type.attr, 346 216 &dev_attr_target_list.attr, 217 + SET_CXL_REGION_ATTR(region) 347 218 NULL, 348 219 }; 349 220 ··· 361 230 362 231 static struct attribute *cxl_decoder_endpoint_attrs[] = { 363 232 &dev_attr_target_type.attr, 233 + &dev_attr_mode.attr, 234 + &dev_attr_dpa_size.attr, 235 + &dev_attr_dpa_resource.attr, 236 + SET_CXL_REGION_ATTR(region) 364 237 NULL, 365 238 }; 366 239 ··· 379 244 NULL, 380 245 }; 381 246 382 - static void cxl_decoder_release(struct device *dev) 247 + static void __cxl_decoder_release(struct cxl_decoder *cxld) 383 248 { 384 - struct cxl_decoder *cxld = to_cxl_decoder(dev); 385 - struct cxl_port *port = to_cxl_port(dev->parent); 249 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 386 250 387 251 ida_free(&port->decoder_ida, cxld->id); 388 - kfree(cxld); 389 252 put_device(&port->dev); 253 + } 254 + 255 + static void cxl_endpoint_decoder_release(struct device *dev) 256 + { 257 + struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev); 258 + 259 + __cxl_decoder_release(&cxled->cxld); 260 + kfree(cxled); 261 + } 262 + 263 + static void cxl_switch_decoder_release(struct device *dev) 264 + { 265 + struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); 266 + 267 + __cxl_decoder_release(&cxlsd->cxld); 268 + kfree(cxlsd); 269 + } 270 + 271 + struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev) 272 + { 273 + if (dev_WARN_ONCE(dev, !is_root_decoder(dev), 274 + "not a cxl_root_decoder device\n")) 275 + return NULL; 276 + return container_of(dev, struct cxl_root_decoder, cxlsd.cxld.dev); 277 + } 278 + EXPORT_SYMBOL_NS_GPL(to_cxl_root_decoder, CXL); 279 + 280 + static void cxl_root_decoder_release(struct device *dev) 281 + { 282 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 283 + 284 + if (atomic_read(&cxlrd->region_id) >= 0) 285 + memregion_free(atomic_read(&cxlrd->region_id)); 286 + __cxl_decoder_release(&cxlrd->cxlsd.cxld); 287 + kfree(cxlrd); 390 288 } 391 289 392 290 static const struct device_type cxl_decoder_endpoint_type = { 393 291 .name = "cxl_decoder_endpoint", 394 - .release = cxl_decoder_release, 292 + .release = cxl_endpoint_decoder_release, 395 293 .groups = cxl_decoder_endpoint_attribute_groups, 396 294 }; 397 295 398 296 static const struct device_type cxl_decoder_switch_type = { 399 297 .name = "cxl_decoder_switch", 400 - .release = cxl_decoder_release, 298 + .release = cxl_switch_decoder_release, 401 299 .groups = cxl_decoder_switch_attribute_groups, 402 300 }; 403 301 404 302 static const struct device_type cxl_decoder_root_type = { 405 303 .name = "cxl_decoder_root", 406 - .release = cxl_decoder_release, 304 + .release = cxl_root_decoder_release, 407 305 .groups = cxl_decoder_root_attribute_groups, 408 306 }; 409 307 ··· 451 283 } 452 284 EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL); 453 285 454 - bool is_cxl_decoder(struct device *dev) 286 + bool is_switch_decoder(struct device *dev) 455 287 { 456 - return dev->type && dev->type->release == cxl_decoder_release; 288 + return is_root_decoder(dev) || dev->type == &cxl_decoder_switch_type; 457 289 } 458 - EXPORT_SYMBOL_NS_GPL(is_cxl_decoder, CXL); 459 290 460 291 struct cxl_decoder *to_cxl_decoder(struct device *dev) 461 292 { 462 - if (dev_WARN_ONCE(dev, dev->type->release != cxl_decoder_release, 293 + if (dev_WARN_ONCE(dev, 294 + !is_switch_decoder(dev) && !is_endpoint_decoder(dev), 463 295 "not a cxl_decoder device\n")) 464 296 return NULL; 465 297 return container_of(dev, struct cxl_decoder, dev); 466 298 } 467 299 EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL); 468 300 301 + struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev) 302 + { 303 + if (dev_WARN_ONCE(dev, !is_endpoint_decoder(dev), 304 + "not a cxl_endpoint_decoder device\n")) 305 + return NULL; 306 + return container_of(dev, struct cxl_endpoint_decoder, cxld.dev); 307 + } 308 + EXPORT_SYMBOL_NS_GPL(to_cxl_endpoint_decoder, CXL); 309 + 310 + struct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev) 311 + { 312 + if (dev_WARN_ONCE(dev, !is_switch_decoder(dev), 313 + "not a cxl_switch_decoder device\n")) 314 + return NULL; 315 + return container_of(dev, struct cxl_switch_decoder, cxld.dev); 316 + } 317 + 469 318 static void cxl_ep_release(struct cxl_ep *ep) 319 + { 320 + put_device(ep->ep); 321 + kfree(ep); 322 + } 323 + 324 + static void cxl_ep_remove(struct cxl_port *port, struct cxl_ep *ep) 470 325 { 471 326 if (!ep) 472 327 return; 473 - list_del(&ep->list); 474 - put_device(ep->ep); 475 - kfree(ep); 328 + xa_erase(&port->endpoints, (unsigned long) ep->ep); 329 + cxl_ep_release(ep); 476 330 } 477 331 478 332 static void cxl_port_release(struct device *dev) 479 333 { 480 334 struct cxl_port *port = to_cxl_port(dev); 481 - struct cxl_ep *ep, *_e; 335 + unsigned long index; 336 + struct cxl_ep *ep; 482 337 483 - device_lock(dev); 484 - list_for_each_entry_safe(ep, _e, &port->endpoints, list) 485 - cxl_ep_release(ep); 486 - device_unlock(dev); 338 + xa_for_each(&port->endpoints, index, ep) 339 + cxl_ep_remove(port, ep); 340 + xa_destroy(&port->endpoints); 341 + xa_destroy(&port->dports); 342 + xa_destroy(&port->regions); 487 343 ida_free(&cxl_port_ida, port->id); 488 344 kfree(port); 489 345 } ··· 562 370 lock_dev = &parent->dev; 563 371 564 372 device_lock_assert(lock_dev); 565 - port->uport = NULL; 373 + port->dead = true; 566 374 device_unregister(&port->dev); 567 375 } 568 376 ··· 587 395 588 396 static struct cxl_port *cxl_port_alloc(struct device *uport, 589 397 resource_size_t component_reg_phys, 590 - struct cxl_port *parent_port) 398 + struct cxl_dport *parent_dport) 591 399 { 592 400 struct cxl_port *port; 593 401 struct device *dev; ··· 601 409 if (rc < 0) 602 410 goto err; 603 411 port->id = rc; 412 + port->uport = uport; 604 413 605 414 /* 606 415 * The top-level cxl_port "cxl_root" does not have a cxl_port as ··· 610 417 * description. 611 418 */ 612 419 dev = &port->dev; 613 - if (parent_port) { 420 + if (parent_dport) { 421 + struct cxl_port *parent_port = parent_dport->port; 422 + struct cxl_port *iter; 423 + 614 424 dev->parent = &parent_port->dev; 615 425 port->depth = parent_port->depth + 1; 426 + port->parent_dport = parent_dport; 427 + 428 + /* 429 + * walk to the host bridge, or the first ancestor that knows 430 + * the host bridge 431 + */ 432 + iter = port; 433 + while (!iter->host_bridge && 434 + !is_cxl_root(to_cxl_port(iter->dev.parent))) 435 + iter = to_cxl_port(iter->dev.parent); 436 + if (iter->host_bridge) 437 + port->host_bridge = iter->host_bridge; 438 + else 439 + port->host_bridge = iter->uport; 440 + dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge)); 616 441 } else 617 442 dev->parent = uport; 618 443 619 - port->uport = uport; 620 444 port->component_reg_phys = component_reg_phys; 621 445 ida_init(&port->decoder_ida); 622 - INIT_LIST_HEAD(&port->dports); 623 - INIT_LIST_HEAD(&port->endpoints); 446 + port->hdm_end = -1; 447 + port->commit_end = -1; 448 + xa_init(&port->dports); 449 + xa_init(&port->endpoints); 450 + xa_init(&port->regions); 624 451 625 452 device_initialize(dev); 626 453 lockdep_set_class_and_subclass(&dev->mutex, &cxl_port_key, port->depth); ··· 660 447 * @host: host device for devm operations 661 448 * @uport: "physical" device implementing this upstream port 662 449 * @component_reg_phys: (optional) for configurable cxl_port instances 663 - * @parent_port: next hop up in the CXL memory decode hierarchy 450 + * @parent_dport: next hop up in the CXL memory decode hierarchy 664 451 */ 665 452 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, 666 453 resource_size_t component_reg_phys, 667 - struct cxl_port *parent_port) 454 + struct cxl_dport *parent_dport) 668 455 { 669 456 struct cxl_port *port; 670 457 struct device *dev; 671 458 int rc; 672 459 673 - port = cxl_port_alloc(uport, component_reg_phys, parent_port); 460 + port = cxl_port_alloc(uport, component_reg_phys, parent_dport); 674 461 if (IS_ERR(port)) 675 462 return port; 676 463 677 464 dev = &port->dev; 678 465 if (is_cxl_memdev(uport)) 679 466 rc = dev_set_name(dev, "endpoint%d", port->id); 680 - else if (parent_port) 467 + else if (parent_dport) 681 468 rc = dev_set_name(dev, "port%d", port->id); 682 469 else 683 470 rc = dev_set_name(dev, "root%d", port->id); ··· 769 556 return 0; 770 557 771 558 port = to_cxl_port(dev); 772 - device_lock(dev); 773 - list_for_each_entry(dport, &port->dports, list) { 774 - iter = match; 775 - while (iter) { 776 - if (iter == dport->dport) 777 - goto out; 778 - iter = iter->parent; 779 - } 559 + iter = match; 560 + while (iter) { 561 + dport = cxl_find_dport_by_dev(port, iter); 562 + if (dport) 563 + break; 564 + iter = iter->parent; 780 565 } 781 - out: 782 - device_unlock(dev); 783 566 784 567 return !!iter; 785 568 } ··· 799 590 static struct cxl_dport *find_dport(struct cxl_port *port, int id) 800 591 { 801 592 struct cxl_dport *dport; 593 + unsigned long index; 802 594 803 595 device_lock_assert(&port->dev); 804 - list_for_each_entry (dport, &port->dports, list) 596 + xa_for_each(&port->dports, index, dport) 805 597 if (dport->port_id == id) 806 598 return dport; 807 599 return NULL; ··· 814 604 815 605 device_lock_assert(&port->dev); 816 606 dup = find_dport(port, new->port_id); 817 - if (dup) 607 + if (dup) { 818 608 dev_err(&port->dev, 819 609 "unable to add dport%d-%s non-unique port id (%s)\n", 820 610 new->port_id, dev_name(new->dport), 821 611 dev_name(dup->dport)); 822 - else 823 - list_add_tail(&new->list, &port->dports); 824 - 825 - return dup ? -EEXIST : 0; 612 + return -EBUSY; 613 + } 614 + return xa_insert(&port->dports, (unsigned long)new->dport, new, 615 + GFP_KERNEL); 826 616 } 827 617 828 618 /* ··· 849 639 struct cxl_dport *dport = data; 850 640 struct cxl_port *port = dport->port; 851 641 642 + xa_erase(&port->dports, (unsigned long) dport->dport); 852 643 put_device(dport->dport); 853 - cond_cxl_root_lock(port); 854 - list_del(&dport->list); 855 - cond_cxl_root_unlock(port); 856 644 } 857 645 858 646 static void cxl_dport_unlink(void *data) ··· 902 694 if (!dport) 903 695 return ERR_PTR(-ENOMEM); 904 696 905 - INIT_LIST_HEAD(&dport->list); 906 697 dport->dport = dport_dev; 907 698 dport->port_id = port_id; 908 699 dport->component_reg_phys = component_reg_phys; ··· 930 723 } 931 724 EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL); 932 725 933 - static struct cxl_ep *find_ep(struct cxl_port *port, struct device *ep_dev) 726 + static int add_ep(struct cxl_ep *new) 934 727 { 935 - struct cxl_ep *ep; 936 - 937 - device_lock_assert(&port->dev); 938 - list_for_each_entry(ep, &port->endpoints, list) 939 - if (ep->ep == ep_dev) 940 - return ep; 941 - return NULL; 942 - } 943 - 944 - static int add_ep(struct cxl_port *port, struct cxl_ep *new) 945 - { 946 - struct cxl_ep *dup; 728 + struct cxl_port *port = new->dport->port; 729 + int rc; 947 730 948 731 device_lock(&port->dev); 949 732 if (port->dead) { 950 733 device_unlock(&port->dev); 951 734 return -ENXIO; 952 735 } 953 - dup = find_ep(port, new->ep); 954 - if (!dup) 955 - list_add_tail(&new->list, &port->endpoints); 736 + rc = xa_insert(&port->endpoints, (unsigned long)new->ep, new, 737 + GFP_KERNEL); 956 738 device_unlock(&port->dev); 957 739 958 - return dup ? -EEXIST : 0; 740 + return rc; 959 741 } 960 742 961 743 /** 962 744 * cxl_add_ep - register an endpoint's interest in a port 963 - * @port: a port in the endpoint's topology ancestry 745 + * @dport: the dport that routes to @ep_dev 964 746 * @ep_dev: device representing the endpoint 965 747 * 966 748 * Intermediate CXL ports are scanned based on the arrival of endpoints. 967 749 * When those endpoints depart the port can be destroyed once all 968 750 * endpoints that care about that port have been removed. 969 751 */ 970 - static int cxl_add_ep(struct cxl_port *port, struct device *ep_dev) 752 + static int cxl_add_ep(struct cxl_dport *dport, struct device *ep_dev) 971 753 { 972 754 struct cxl_ep *ep; 973 755 int rc; ··· 965 769 if (!ep) 966 770 return -ENOMEM; 967 771 968 - INIT_LIST_HEAD(&ep->list); 969 772 ep->ep = get_device(ep_dev); 773 + ep->dport = dport; 970 774 971 - rc = add_ep(port, ep); 775 + rc = add_ep(ep); 972 776 if (rc) 973 777 cxl_ep_release(ep); 974 778 return rc; ··· 977 781 struct cxl_find_port_ctx { 978 782 const struct device *dport_dev; 979 783 const struct cxl_port *parent_port; 784 + struct cxl_dport **dport; 980 785 }; 981 786 982 787 static int match_port_by_dport(struct device *dev, const void *data) 983 788 { 984 789 const struct cxl_find_port_ctx *ctx = data; 790 + struct cxl_dport *dport; 985 791 struct cxl_port *port; 986 792 987 793 if (!is_cxl_port(dev)) ··· 992 794 return 0; 993 795 994 796 port = to_cxl_port(dev); 995 - return cxl_find_dport_by_dev(port, ctx->dport_dev) != NULL; 797 + dport = cxl_find_dport_by_dev(port, ctx->dport_dev); 798 + if (ctx->dport) 799 + *ctx->dport = dport; 800 + return dport != NULL; 996 801 } 997 802 998 803 static struct cxl_port *__find_cxl_port(struct cxl_find_port_ctx *ctx) ··· 1011 810 return NULL; 1012 811 } 1013 812 1014 - static struct cxl_port *find_cxl_port(struct device *dport_dev) 813 + static struct cxl_port *find_cxl_port(struct device *dport_dev, 814 + struct cxl_dport **dport) 1015 815 { 1016 816 struct cxl_find_port_ctx ctx = { 1017 817 .dport_dev = dport_dev, 818 + .dport = dport, 1018 819 }; 820 + struct cxl_port *port; 1019 821 1020 - return __find_cxl_port(&ctx); 822 + port = __find_cxl_port(&ctx); 823 + return port; 1021 824 } 1022 825 1023 826 static struct cxl_port *find_cxl_port_at(struct cxl_port *parent_port, 1024 - struct device *dport_dev) 827 + struct device *dport_dev, 828 + struct cxl_dport **dport) 1025 829 { 1026 830 struct cxl_find_port_ctx ctx = { 1027 831 .dport_dev = dport_dev, 1028 832 .parent_port = parent_port, 833 + .dport = dport, 1029 834 }; 835 + struct cxl_port *port; 1030 836 1031 - return __find_cxl_port(&ctx); 837 + port = __find_cxl_port(&ctx); 838 + return port; 1032 839 } 1033 840 1034 841 /* ··· 1060 851 struct cxl_port *parent_port; 1061 852 struct device *parent; 1062 853 1063 - parent_port = cxl_mem_find_port(cxlmd); 854 + parent_port = cxl_mem_find_port(cxlmd, NULL); 1064 855 if (!parent_port) 1065 856 goto out; 1066 857 parent = &parent_port->dev; 1067 858 1068 859 device_lock(parent); 1069 - if (parent->driver && endpoint->uport) { 860 + if (parent->driver && !endpoint->dead) { 1070 861 devm_release_action(parent, cxl_unlink_uport, endpoint); 1071 862 devm_release_action(parent, unregister_port, endpoint); 1072 863 } ··· 1092 883 * for a port to be unregistered is when all memdevs beneath that port have gone 1093 884 * through ->remove(). This "bottom-up" removal selectively removes individual 1094 885 * child ports manually. This depends on devm_cxl_add_port() to not change is 1095 - * devm action registration order. 886 + * devm action registration order, and for dports to have already been 887 + * destroyed by reap_dports(). 1096 888 */ 1097 - static void delete_switch_port(struct cxl_port *port, struct list_head *dports) 889 + static void delete_switch_port(struct cxl_port *port) 1098 890 { 1099 - struct cxl_dport *dport, *_d; 891 + devm_release_action(port->dev.parent, cxl_unlink_uport, port); 892 + devm_release_action(port->dev.parent, unregister_port, port); 893 + } 1100 894 1101 - list_for_each_entry_safe(dport, _d, dports, list) { 895 + static void reap_dports(struct cxl_port *port) 896 + { 897 + struct cxl_dport *dport; 898 + unsigned long index; 899 + 900 + device_lock_assert(&port->dev); 901 + 902 + xa_for_each(&port->dports, index, dport) { 1102 903 devm_release_action(&port->dev, cxl_dport_unlink, dport); 1103 904 devm_release_action(&port->dev, cxl_dport_remove, dport); 1104 905 devm_kfree(&port->dev, dport); 1105 906 } 1106 - devm_release_action(port->dev.parent, cxl_unlink_uport, port); 1107 - devm_release_action(port->dev.parent, unregister_port, port); 1108 907 } 908 + 909 + int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd, 910 + struct cxl_dport *parent_dport) 911 + { 912 + struct cxl_port *parent_port = parent_dport->port; 913 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 914 + struct cxl_port *endpoint, *iter, *down; 915 + int rc; 916 + 917 + /* 918 + * Now that the path to the root is established record all the 919 + * intervening ports in the chain. 920 + */ 921 + for (iter = parent_port, down = NULL; !is_cxl_root(iter); 922 + down = iter, iter = to_cxl_port(iter->dev.parent)) { 923 + struct cxl_ep *ep; 924 + 925 + ep = cxl_ep_load(iter, cxlmd); 926 + ep->next = down; 927 + } 928 + 929 + endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev, 930 + cxlds->component_reg_phys, parent_dport); 931 + if (IS_ERR(endpoint)) 932 + return PTR_ERR(endpoint); 933 + 934 + dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev)); 935 + 936 + rc = cxl_endpoint_autoremove(cxlmd, endpoint); 937 + if (rc) 938 + return rc; 939 + 940 + if (!endpoint->dev.driver) { 941 + dev_err(&cxlmd->dev, "%s failed probe\n", 942 + dev_name(&endpoint->dev)); 943 + return -ENXIO; 944 + } 945 + 946 + return 0; 947 + } 948 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_endpoint, CXL); 1109 949 1110 950 static void cxl_detach_ep(void *data) 1111 951 { ··· 1164 906 for (iter = &cxlmd->dev; iter; iter = grandparent(iter)) { 1165 907 struct device *dport_dev = grandparent(iter); 1166 908 struct cxl_port *port, *parent_port; 1167 - LIST_HEAD(reap_dports); 1168 909 struct cxl_ep *ep; 910 + bool died = false; 1169 911 1170 912 if (!dport_dev) 1171 913 break; 1172 914 1173 - port = find_cxl_port(dport_dev); 915 + port = find_cxl_port(dport_dev, NULL); 1174 916 if (!port) 1175 917 continue; 1176 918 ··· 1194 936 } 1195 937 1196 938 device_lock(&port->dev); 1197 - ep = find_ep(port, &cxlmd->dev); 939 + ep = cxl_ep_load(port, cxlmd); 1198 940 dev_dbg(&cxlmd->dev, "disconnect %s from %s\n", 1199 941 ep ? dev_name(ep->ep) : "", dev_name(&port->dev)); 1200 - cxl_ep_release(ep); 1201 - if (ep && !port->dead && list_empty(&port->endpoints) && 942 + cxl_ep_remove(port, ep); 943 + if (ep && !port->dead && xa_empty(&port->endpoints) && 1202 944 !is_cxl_root(parent_port)) { 1203 945 /* 1204 946 * This was the last ep attached to a dynamically 1205 947 * enumerated port. Block new cxl_add_ep() and garbage 1206 948 * collect the port. 1207 949 */ 950 + died = true; 1208 951 port->dead = true; 1209 - list_splice_init(&port->dports, &reap_dports); 952 + reap_dports(port); 1210 953 } 1211 954 device_unlock(&port->dev); 1212 955 1213 - if (!list_empty(&reap_dports)) { 956 + if (died) { 1214 957 dev_dbg(&cxlmd->dev, "delete %s\n", 1215 958 dev_name(&port->dev)); 1216 - delete_switch_port(port, &reap_dports); 959 + delete_switch_port(port); 1217 960 } 1218 961 put_device(&port->dev); 1219 962 device_unlock(&parent_port->dev); ··· 1245 986 { 1246 987 struct device *dparent = grandparent(dport_dev); 1247 988 struct cxl_port *port, *parent_port = NULL; 989 + struct cxl_dport *dport, *parent_dport; 1248 990 resource_size_t component_reg_phys; 1249 991 int rc; 1250 992 ··· 1260 1000 return -ENXIO; 1261 1001 } 1262 1002 1263 - parent_port = find_cxl_port(dparent); 1003 + parent_port = find_cxl_port(dparent, &parent_dport); 1264 1004 if (!parent_port) { 1265 1005 /* iterate to create this parent_port */ 1266 1006 return -EAGAIN; ··· 1275 1015 goto out; 1276 1016 } 1277 1017 1278 - port = find_cxl_port_at(parent_port, dport_dev); 1018 + port = find_cxl_port_at(parent_port, dport_dev, &dport); 1279 1019 if (!port) { 1280 1020 component_reg_phys = find_component_registers(uport_dev); 1281 1021 port = devm_cxl_add_port(&parent_port->dev, uport_dev, 1282 - component_reg_phys, parent_port); 1022 + component_reg_phys, parent_dport); 1023 + /* retry find to pick up the new dport information */ 1283 1024 if (!IS_ERR(port)) 1284 - get_device(&port->dev); 1025 + port = find_cxl_port_at(parent_port, dport_dev, &dport); 1285 1026 } 1286 1027 out: 1287 1028 device_unlock(&parent_port->dev); ··· 1292 1031 else { 1293 1032 dev_dbg(&cxlmd->dev, "add to new port %s:%s\n", 1294 1033 dev_name(&port->dev), dev_name(port->uport)); 1295 - rc = cxl_add_ep(port, &cxlmd->dev); 1296 - if (rc == -EEXIST) { 1034 + rc = cxl_add_ep(dport, &cxlmd->dev); 1035 + if (rc == -EBUSY) { 1297 1036 /* 1298 1037 * "can't" happen, but this error code means 1299 1038 * something to the caller, so translate it. ··· 1326 1065 for (iter = dev; iter; iter = grandparent(iter)) { 1327 1066 struct device *dport_dev = grandparent(iter); 1328 1067 struct device *uport_dev; 1068 + struct cxl_dport *dport; 1329 1069 struct cxl_port *port; 1330 1070 1331 1071 if (!dport_dev) ··· 1342 1080 dev_dbg(dev, "scan: iter: %s dport_dev: %s parent: %s\n", 1343 1081 dev_name(iter), dev_name(dport_dev), 1344 1082 dev_name(uport_dev)); 1345 - port = find_cxl_port(dport_dev); 1083 + port = find_cxl_port(dport_dev, &dport); 1346 1084 if (port) { 1347 1085 dev_dbg(&cxlmd->dev, 1348 1086 "found already registered port %s:%s\n", 1349 1087 dev_name(&port->dev), dev_name(port->uport)); 1350 - rc = cxl_add_ep(port, &cxlmd->dev); 1088 + rc = cxl_add_ep(dport, &cxlmd->dev); 1351 1089 1352 1090 /* 1353 1091 * If the endpoint already exists in the port's list, ··· 1356 1094 * the parent_port lock as the current port may be being 1357 1095 * reaped. 1358 1096 */ 1359 - if (rc && rc != -EEXIST) { 1097 + if (rc && rc != -EBUSY) { 1360 1098 put_device(&port->dev); 1361 1099 return rc; 1362 1100 } ··· 1386 1124 } 1387 1125 EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL); 1388 1126 1389 - struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd) 1127 + struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, 1128 + struct cxl_dport **dport) 1390 1129 { 1391 - return find_cxl_port(grandparent(&cxlmd->dev)); 1130 + return find_cxl_port(grandparent(&cxlmd->dev), dport); 1392 1131 } 1393 1132 EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL); 1394 1133 1395 - struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port, 1396 - const struct device *dev) 1397 - { 1398 - struct cxl_dport *dport; 1399 - 1400 - device_lock(&port->dev); 1401 - list_for_each_entry(dport, &port->dports, list) 1402 - if (dport->dport == dev) { 1403 - device_unlock(&port->dev); 1404 - return dport; 1405 - } 1406 - 1407 - device_unlock(&port->dev); 1408 - return NULL; 1409 - } 1410 - EXPORT_SYMBOL_NS_GPL(cxl_find_dport_by_dev, CXL); 1411 - 1412 - static int decoder_populate_targets(struct cxl_decoder *cxld, 1134 + static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, 1413 1135 struct cxl_port *port, int *target_map) 1414 1136 { 1415 1137 int i, rc = 0; ··· 1403 1157 1404 1158 device_lock_assert(&port->dev); 1405 1159 1406 - if (list_empty(&port->dports)) 1160 + if (xa_empty(&port->dports)) 1407 1161 return -EINVAL; 1408 1162 1409 - write_seqlock(&cxld->target_lock); 1410 - for (i = 0; i < cxld->nr_targets; i++) { 1163 + write_seqlock(&cxlsd->target_lock); 1164 + for (i = 0; i < cxlsd->nr_targets; i++) { 1411 1165 struct cxl_dport *dport = find_dport(port, target_map[i]); 1412 1166 1413 1167 if (!dport) { 1414 1168 rc = -ENXIO; 1415 1169 break; 1416 1170 } 1417 - cxld->target[i] = dport; 1171 + cxlsd->target[i] = dport; 1418 1172 } 1419 - write_sequnlock(&cxld->target_lock); 1173 + write_sequnlock(&cxlsd->target_lock); 1420 1174 1421 1175 return rc; 1176 + } 1177 + 1178 + static struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos) 1179 + { 1180 + struct cxl_switch_decoder *cxlsd = &cxlrd->cxlsd; 1181 + struct cxl_decoder *cxld = &cxlsd->cxld; 1182 + int iw; 1183 + 1184 + iw = cxld->interleave_ways; 1185 + if (dev_WARN_ONCE(&cxld->dev, iw != cxlsd->nr_targets, 1186 + "misconfigured root decoder\n")) 1187 + return NULL; 1188 + 1189 + return cxlrd->cxlsd.target[pos % iw]; 1422 1190 } 1423 1191 1424 1192 static struct lock_class_key cxl_decoder_key; 1425 1193 1426 1194 /** 1427 - * cxl_decoder_alloc - Allocate a new CXL decoder 1195 + * cxl_decoder_init - Common decoder setup / initialization 1428 1196 * @port: owning port of this decoder 1429 - * @nr_targets: downstream targets accessible by this decoder. All upstream 1430 - * ports and root ports must have at least 1 target. Endpoint 1431 - * devices will have 0 targets. Callers wishing to register an 1432 - * endpoint device should specify 0. 1197 + * @cxld: common decoder properties to initialize 1433 1198 * 1434 - * A port should contain one or more decoders. Each of those decoders enable 1435 - * some address space for CXL.mem utilization. A decoder is expected to be 1436 - * configured by the caller before registering. 1437 - * 1438 - * Return: A new cxl decoder to be registered by cxl_decoder_add(). The decoder 1439 - * is initialized to be a "passthrough" decoder. 1199 + * A port may contain one or more decoders. Each of those decoders 1200 + * enable some address space for CXL.mem utilization. A decoder is 1201 + * expected to be configured by the caller before registering via 1202 + * cxl_decoder_add() 1440 1203 */ 1441 - static struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, 1442 - unsigned int nr_targets) 1204 + static int cxl_decoder_init(struct cxl_port *port, struct cxl_decoder *cxld) 1443 1205 { 1444 - struct cxl_decoder *cxld; 1445 1206 struct device *dev; 1446 - int rc = 0; 1447 - 1448 - if (nr_targets > CXL_DECODER_MAX_INTERLEAVE) 1449 - return ERR_PTR(-EINVAL); 1450 - 1451 - cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL); 1452 - if (!cxld) 1453 - return ERR_PTR(-ENOMEM); 1207 + int rc; 1454 1208 1455 1209 rc = ida_alloc(&port->decoder_ida, GFP_KERNEL); 1456 1210 if (rc < 0) 1457 - goto err; 1211 + return rc; 1458 1212 1459 1213 /* need parent to stick around to release the id */ 1460 1214 get_device(&port->dev); 1461 1215 cxld->id = rc; 1462 1216 1463 - cxld->nr_targets = nr_targets; 1464 - seqlock_init(&cxld->target_lock); 1465 1217 dev = &cxld->dev; 1466 1218 device_initialize(dev); 1467 1219 lockdep_set_class(&dev->mutex, &cxl_decoder_key); 1468 1220 device_set_pm_not_required(dev); 1469 1221 dev->parent = &port->dev; 1470 1222 dev->bus = &cxl_bus_type; 1471 - if (is_cxl_root(port)) 1472 - cxld->dev.type = &cxl_decoder_root_type; 1473 - else if (is_cxl_endpoint(port)) 1474 - cxld->dev.type = &cxl_decoder_endpoint_type; 1475 - else 1476 - cxld->dev.type = &cxl_decoder_switch_type; 1477 1223 1478 1224 /* Pre initialize an "empty" decoder */ 1479 1225 cxld->interleave_ways = 1; 1480 1226 cxld->interleave_granularity = PAGE_SIZE; 1481 1227 cxld->target_type = CXL_DECODER_EXPANDER; 1482 - cxld->platform_res = (struct resource)DEFINE_RES_MEM(0, 0); 1228 + cxld->hpa_range = (struct range) { 1229 + .start = 0, 1230 + .end = -1, 1231 + }; 1483 1232 1484 - return cxld; 1485 - err: 1486 - kfree(cxld); 1487 - return ERR_PTR(rc); 1233 + return 0; 1234 + } 1235 + 1236 + static int cxl_switch_decoder_init(struct cxl_port *port, 1237 + struct cxl_switch_decoder *cxlsd, 1238 + int nr_targets) 1239 + { 1240 + if (nr_targets > CXL_DECODER_MAX_INTERLEAVE) 1241 + return -EINVAL; 1242 + 1243 + cxlsd->nr_targets = nr_targets; 1244 + seqlock_init(&cxlsd->target_lock); 1245 + return cxl_decoder_init(port, &cxlsd->cxld); 1488 1246 } 1489 1247 1490 1248 /** ··· 1501 1251 * firmware description of CXL resources into a CXL standard decode 1502 1252 * topology. 1503 1253 */ 1504 - struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 1505 - unsigned int nr_targets) 1254 + struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 1255 + unsigned int nr_targets) 1506 1256 { 1257 + struct cxl_root_decoder *cxlrd; 1258 + struct cxl_switch_decoder *cxlsd; 1259 + struct cxl_decoder *cxld; 1260 + int rc; 1261 + 1507 1262 if (!is_cxl_root(port)) 1508 1263 return ERR_PTR(-EINVAL); 1509 1264 1510 - return cxl_decoder_alloc(port, nr_targets); 1265 + cxlrd = kzalloc(struct_size(cxlrd, cxlsd.target, nr_targets), 1266 + GFP_KERNEL); 1267 + if (!cxlrd) 1268 + return ERR_PTR(-ENOMEM); 1269 + 1270 + cxlsd = &cxlrd->cxlsd; 1271 + rc = cxl_switch_decoder_init(port, cxlsd, nr_targets); 1272 + if (rc) { 1273 + kfree(cxlrd); 1274 + return ERR_PTR(rc); 1275 + } 1276 + 1277 + cxlrd->calc_hb = cxl_hb_modulo; 1278 + 1279 + cxld = &cxlsd->cxld; 1280 + cxld->dev.type = &cxl_decoder_root_type; 1281 + /* 1282 + * cxl_root_decoder_release() special cases negative ids to 1283 + * detect memregion_alloc() failures. 1284 + */ 1285 + atomic_set(&cxlrd->region_id, -1); 1286 + rc = memregion_alloc(GFP_KERNEL); 1287 + if (rc < 0) { 1288 + put_device(&cxld->dev); 1289 + return ERR_PTR(rc); 1290 + } 1291 + 1292 + atomic_set(&cxlrd->region_id, rc); 1293 + return cxlrd; 1511 1294 } 1512 1295 EXPORT_SYMBOL_NS_GPL(cxl_root_decoder_alloc, CXL); 1513 1296 ··· 1555 1272 * that sit between Switch Upstream Ports / Switch Downstream Ports and 1556 1273 * Host Bridges / Root Ports. 1557 1274 */ 1558 - struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 1559 - unsigned int nr_targets) 1275 + struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 1276 + unsigned int nr_targets) 1560 1277 { 1278 + struct cxl_switch_decoder *cxlsd; 1279 + struct cxl_decoder *cxld; 1280 + int rc; 1281 + 1561 1282 if (is_cxl_root(port) || is_cxl_endpoint(port)) 1562 1283 return ERR_PTR(-EINVAL); 1563 1284 1564 - return cxl_decoder_alloc(port, nr_targets); 1285 + cxlsd = kzalloc(struct_size(cxlsd, target, nr_targets), GFP_KERNEL); 1286 + if (!cxlsd) 1287 + return ERR_PTR(-ENOMEM); 1288 + 1289 + rc = cxl_switch_decoder_init(port, cxlsd, nr_targets); 1290 + if (rc) { 1291 + kfree(cxlsd); 1292 + return ERR_PTR(rc); 1293 + } 1294 + 1295 + cxld = &cxlsd->cxld; 1296 + cxld->dev.type = &cxl_decoder_switch_type; 1297 + return cxlsd; 1565 1298 } 1566 1299 EXPORT_SYMBOL_NS_GPL(cxl_switch_decoder_alloc, CXL); 1567 1300 ··· 1587 1288 * 1588 1289 * Return: A new cxl decoder to be registered by cxl_decoder_add() 1589 1290 */ 1590 - struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port) 1291 + struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port) 1591 1292 { 1293 + struct cxl_endpoint_decoder *cxled; 1294 + struct cxl_decoder *cxld; 1295 + int rc; 1296 + 1592 1297 if (!is_cxl_endpoint(port)) 1593 1298 return ERR_PTR(-EINVAL); 1594 1299 1595 - return cxl_decoder_alloc(port, 0); 1300 + cxled = kzalloc(sizeof(*cxled), GFP_KERNEL); 1301 + if (!cxled) 1302 + return ERR_PTR(-ENOMEM); 1303 + 1304 + cxled->pos = -1; 1305 + cxld = &cxled->cxld; 1306 + rc = cxl_decoder_init(port, cxld); 1307 + if (rc) { 1308 + kfree(cxled); 1309 + return ERR_PTR(rc); 1310 + } 1311 + 1312 + cxld->dev.type = &cxl_decoder_endpoint_type; 1313 + return cxled; 1596 1314 } 1597 1315 EXPORT_SYMBOL_NS_GPL(cxl_endpoint_decoder_alloc, CXL); 1598 1316 1599 1317 /** 1600 1318 * cxl_decoder_add_locked - Add a decoder with targets 1601 - * @cxld: The cxl decoder allocated by cxl_decoder_alloc() 1319 + * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc() 1602 1320 * @target_map: A list of downstream ports that this decoder can direct memory 1603 1321 * traffic to. These numbers should correspond with the port number 1604 1322 * in the PCIe Link Capabilities structure. ··· 1651 1335 1652 1336 port = to_cxl_port(cxld->dev.parent); 1653 1337 if (!is_endpoint_decoder(dev)) { 1654 - rc = decoder_populate_targets(cxld, port, target_map); 1338 + struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); 1339 + 1340 + rc = decoder_populate_targets(cxlsd, port, target_map); 1655 1341 if (rc && (cxld->flags & CXL_DECODER_F_ENABLE)) { 1656 1342 dev_err(&port->dev, 1657 1343 "Failed to populate active decoder targets\n"); ··· 1665 1347 if (rc) 1666 1348 return rc; 1667 1349 1668 - /* 1669 - * Platform decoder resources should show up with a reasonable name. All 1670 - * other resources are just sub ranges within the main decoder resource. 1671 - */ 1672 - if (is_root_decoder(dev)) 1673 - cxld->platform_res.name = dev_name(dev); 1674 - 1675 1350 return device_add(dev); 1676 1351 } 1677 1352 EXPORT_SYMBOL_NS_GPL(cxl_decoder_add_locked, CXL); 1678 1353 1679 1354 /** 1680 1355 * cxl_decoder_add - Add a decoder with targets 1681 - * @cxld: The cxl decoder allocated by cxl_decoder_alloc() 1356 + * @cxld: The cxl decoder allocated by cxl_<type>_decoder_alloc() 1682 1357 * @target_map: A list of downstream ports that this decoder can direct memory 1683 1358 * traffic to. These numbers should correspond with the port number 1684 1359 * in the PCIe Link Capabilities structure. ··· 1705 1394 1706 1395 static void cxld_unregister(void *dev) 1707 1396 { 1397 + struct cxl_endpoint_decoder *cxled; 1398 + 1399 + if (is_endpoint_decoder(dev)) { 1400 + cxled = to_cxl_endpoint_decoder(dev); 1401 + cxl_decoder_kill_region(cxled); 1402 + } 1403 + 1708 1404 device_unregister(dev); 1709 1405 } 1710 1406 ··· 1839 1521 }; 1840 1522 EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL); 1841 1523 1524 + static struct dentry *cxl_debugfs; 1525 + 1526 + struct dentry *cxl_debugfs_create_dir(const char *dir) 1527 + { 1528 + return debugfs_create_dir(dir, cxl_debugfs); 1529 + } 1530 + EXPORT_SYMBOL_NS_GPL(cxl_debugfs_create_dir, CXL); 1531 + 1842 1532 static __init int cxl_core_init(void) 1843 1533 { 1844 1534 int rc; 1535 + 1536 + cxl_debugfs = debugfs_create_dir("cxl", NULL); 1845 1537 1846 1538 cxl_mbox_init(); 1847 1539 ··· 1869 1541 if (rc) 1870 1542 goto err_bus; 1871 1543 1544 + rc = cxl_region_init(); 1545 + if (rc) 1546 + goto err_region; 1547 + 1872 1548 return 0; 1873 1549 1550 + err_region: 1551 + bus_unregister(&cxl_bus_type); 1874 1552 err_bus: 1875 1553 destroy_workqueue(cxl_bus_wq); 1876 1554 err_wq: 1877 1555 cxl_memdev_exit(); 1878 - cxl_mbox_exit(); 1879 1556 return rc; 1880 1557 } 1881 1558 1882 1559 static void cxl_core_exit(void) 1883 1560 { 1561 + cxl_region_exit(); 1884 1562 bus_unregister(&cxl_bus_type); 1885 1563 destroy_workqueue(cxl_bus_wq); 1886 1564 cxl_memdev_exit(); 1887 - cxl_mbox_exit(); 1565 + debugfs_remove_recursive(cxl_debugfs); 1888 1566 } 1889 1567 1890 1568 module_init(cxl_core_init);
+1896
drivers/cxl/core/region.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 + #include <linux/memregion.h> 4 + #include <linux/genalloc.h> 5 + #include <linux/device.h> 6 + #include <linux/module.h> 7 + #include <linux/slab.h> 8 + #include <linux/uuid.h> 9 + #include <linux/idr.h> 10 + #include <cxlmem.h> 11 + #include <cxl.h> 12 + #include "core.h" 13 + 14 + /** 15 + * DOC: cxl core region 16 + * 17 + * CXL Regions represent mapped memory capacity in system physical address 18 + * space. Whereas the CXL Root Decoders identify the bounds of potential CXL 19 + * Memory ranges, Regions represent the active mapped capacity by the HDM 20 + * Decoder Capability structures throughout the Host Bridges, Switches, and 21 + * Endpoints in the topology. 22 + * 23 + * Region configuration has ordering constraints. UUID may be set at any time 24 + * but is only visible for persistent regions. 25 + * 1. Interleave granularity 26 + * 2. Interleave size 27 + * 3. Decoder targets 28 + */ 29 + 30 + /* 31 + * All changes to the interleave configuration occur with this lock held 32 + * for write. 33 + */ 34 + static DECLARE_RWSEM(cxl_region_rwsem); 35 + 36 + static struct cxl_region *to_cxl_region(struct device *dev); 37 + 38 + static ssize_t uuid_show(struct device *dev, struct device_attribute *attr, 39 + char *buf) 40 + { 41 + struct cxl_region *cxlr = to_cxl_region(dev); 42 + struct cxl_region_params *p = &cxlr->params; 43 + ssize_t rc; 44 + 45 + rc = down_read_interruptible(&cxl_region_rwsem); 46 + if (rc) 47 + return rc; 48 + rc = sysfs_emit(buf, "%pUb\n", &p->uuid); 49 + up_read(&cxl_region_rwsem); 50 + 51 + return rc; 52 + } 53 + 54 + static int is_dup(struct device *match, void *data) 55 + { 56 + struct cxl_region_params *p; 57 + struct cxl_region *cxlr; 58 + uuid_t *uuid = data; 59 + 60 + if (!is_cxl_region(match)) 61 + return 0; 62 + 63 + lockdep_assert_held(&cxl_region_rwsem); 64 + cxlr = to_cxl_region(match); 65 + p = &cxlr->params; 66 + 67 + if (uuid_equal(&p->uuid, uuid)) { 68 + dev_dbg(match, "already has uuid: %pUb\n", uuid); 69 + return -EBUSY; 70 + } 71 + 72 + return 0; 73 + } 74 + 75 + static ssize_t uuid_store(struct device *dev, struct device_attribute *attr, 76 + const char *buf, size_t len) 77 + { 78 + struct cxl_region *cxlr = to_cxl_region(dev); 79 + struct cxl_region_params *p = &cxlr->params; 80 + uuid_t temp; 81 + ssize_t rc; 82 + 83 + if (len != UUID_STRING_LEN + 1) 84 + return -EINVAL; 85 + 86 + rc = uuid_parse(buf, &temp); 87 + if (rc) 88 + return rc; 89 + 90 + if (uuid_is_null(&temp)) 91 + return -EINVAL; 92 + 93 + rc = down_write_killable(&cxl_region_rwsem); 94 + if (rc) 95 + return rc; 96 + 97 + if (uuid_equal(&p->uuid, &temp)) 98 + goto out; 99 + 100 + rc = -EBUSY; 101 + if (p->state >= CXL_CONFIG_ACTIVE) 102 + goto out; 103 + 104 + rc = bus_for_each_dev(&cxl_bus_type, NULL, &temp, is_dup); 105 + if (rc < 0) 106 + goto out; 107 + 108 + uuid_copy(&p->uuid, &temp); 109 + out: 110 + up_write(&cxl_region_rwsem); 111 + 112 + if (rc) 113 + return rc; 114 + return len; 115 + } 116 + static DEVICE_ATTR_RW(uuid); 117 + 118 + static struct cxl_region_ref *cxl_rr_load(struct cxl_port *port, 119 + struct cxl_region *cxlr) 120 + { 121 + return xa_load(&port->regions, (unsigned long)cxlr); 122 + } 123 + 124 + static int cxl_region_decode_reset(struct cxl_region *cxlr, int count) 125 + { 126 + struct cxl_region_params *p = &cxlr->params; 127 + int i; 128 + 129 + for (i = count - 1; i >= 0; i--) { 130 + struct cxl_endpoint_decoder *cxled = p->targets[i]; 131 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 132 + struct cxl_port *iter = cxled_to_port(cxled); 133 + struct cxl_ep *ep; 134 + int rc; 135 + 136 + while (!is_cxl_root(to_cxl_port(iter->dev.parent))) 137 + iter = to_cxl_port(iter->dev.parent); 138 + 139 + for (ep = cxl_ep_load(iter, cxlmd); iter; 140 + iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) { 141 + struct cxl_region_ref *cxl_rr; 142 + struct cxl_decoder *cxld; 143 + 144 + cxl_rr = cxl_rr_load(iter, cxlr); 145 + cxld = cxl_rr->decoder; 146 + rc = cxld->reset(cxld); 147 + if (rc) 148 + return rc; 149 + } 150 + 151 + rc = cxled->cxld.reset(&cxled->cxld); 152 + if (rc) 153 + return rc; 154 + } 155 + 156 + return 0; 157 + } 158 + 159 + static int cxl_region_decode_commit(struct cxl_region *cxlr) 160 + { 161 + struct cxl_region_params *p = &cxlr->params; 162 + int i, rc = 0; 163 + 164 + for (i = 0; i < p->nr_targets; i++) { 165 + struct cxl_endpoint_decoder *cxled = p->targets[i]; 166 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 167 + struct cxl_region_ref *cxl_rr; 168 + struct cxl_decoder *cxld; 169 + struct cxl_port *iter; 170 + struct cxl_ep *ep; 171 + 172 + /* commit bottom up */ 173 + for (iter = cxled_to_port(cxled); !is_cxl_root(iter); 174 + iter = to_cxl_port(iter->dev.parent)) { 175 + cxl_rr = cxl_rr_load(iter, cxlr); 176 + cxld = cxl_rr->decoder; 177 + rc = cxld->commit(cxld); 178 + if (rc) 179 + break; 180 + } 181 + 182 + if (rc) { 183 + /* programming @iter failed, teardown */ 184 + for (ep = cxl_ep_load(iter, cxlmd); ep && iter; 185 + iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) { 186 + cxl_rr = cxl_rr_load(iter, cxlr); 187 + cxld = cxl_rr->decoder; 188 + cxld->reset(cxld); 189 + } 190 + 191 + cxled->cxld.reset(&cxled->cxld); 192 + goto err; 193 + } 194 + } 195 + 196 + return 0; 197 + 198 + err: 199 + /* undo the targets that were successfully committed */ 200 + cxl_region_decode_reset(cxlr, i); 201 + return rc; 202 + } 203 + 204 + static ssize_t commit_store(struct device *dev, struct device_attribute *attr, 205 + const char *buf, size_t len) 206 + { 207 + struct cxl_region *cxlr = to_cxl_region(dev); 208 + struct cxl_region_params *p = &cxlr->params; 209 + bool commit; 210 + ssize_t rc; 211 + 212 + rc = kstrtobool(buf, &commit); 213 + if (rc) 214 + return rc; 215 + 216 + rc = down_write_killable(&cxl_region_rwsem); 217 + if (rc) 218 + return rc; 219 + 220 + /* Already in the requested state? */ 221 + if (commit && p->state >= CXL_CONFIG_COMMIT) 222 + goto out; 223 + if (!commit && p->state < CXL_CONFIG_COMMIT) 224 + goto out; 225 + 226 + /* Not ready to commit? */ 227 + if (commit && p->state < CXL_CONFIG_ACTIVE) { 228 + rc = -ENXIO; 229 + goto out; 230 + } 231 + 232 + if (commit) 233 + rc = cxl_region_decode_commit(cxlr); 234 + else { 235 + p->state = CXL_CONFIG_RESET_PENDING; 236 + up_write(&cxl_region_rwsem); 237 + device_release_driver(&cxlr->dev); 238 + down_write(&cxl_region_rwsem); 239 + 240 + /* 241 + * The lock was dropped, so need to revalidate that the reset is 242 + * still pending. 243 + */ 244 + if (p->state == CXL_CONFIG_RESET_PENDING) 245 + rc = cxl_region_decode_reset(cxlr, p->interleave_ways); 246 + } 247 + 248 + if (rc) 249 + goto out; 250 + 251 + if (commit) 252 + p->state = CXL_CONFIG_COMMIT; 253 + else if (p->state == CXL_CONFIG_RESET_PENDING) 254 + p->state = CXL_CONFIG_ACTIVE; 255 + 256 + out: 257 + up_write(&cxl_region_rwsem); 258 + 259 + if (rc) 260 + return rc; 261 + return len; 262 + } 263 + 264 + static ssize_t commit_show(struct device *dev, struct device_attribute *attr, 265 + char *buf) 266 + { 267 + struct cxl_region *cxlr = to_cxl_region(dev); 268 + struct cxl_region_params *p = &cxlr->params; 269 + ssize_t rc; 270 + 271 + rc = down_read_interruptible(&cxl_region_rwsem); 272 + if (rc) 273 + return rc; 274 + rc = sysfs_emit(buf, "%d\n", p->state >= CXL_CONFIG_COMMIT); 275 + up_read(&cxl_region_rwsem); 276 + 277 + return rc; 278 + } 279 + static DEVICE_ATTR_RW(commit); 280 + 281 + static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a, 282 + int n) 283 + { 284 + struct device *dev = kobj_to_dev(kobj); 285 + struct cxl_region *cxlr = to_cxl_region(dev); 286 + 287 + if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM) 288 + return 0; 289 + return a->mode; 290 + } 291 + 292 + static ssize_t interleave_ways_show(struct device *dev, 293 + struct device_attribute *attr, char *buf) 294 + { 295 + struct cxl_region *cxlr = to_cxl_region(dev); 296 + struct cxl_region_params *p = &cxlr->params; 297 + ssize_t rc; 298 + 299 + rc = down_read_interruptible(&cxl_region_rwsem); 300 + if (rc) 301 + return rc; 302 + rc = sysfs_emit(buf, "%d\n", p->interleave_ways); 303 + up_read(&cxl_region_rwsem); 304 + 305 + return rc; 306 + } 307 + 308 + static const struct attribute_group *get_cxl_region_target_group(void); 309 + 310 + static ssize_t interleave_ways_store(struct device *dev, 311 + struct device_attribute *attr, 312 + const char *buf, size_t len) 313 + { 314 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent); 315 + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 316 + struct cxl_region *cxlr = to_cxl_region(dev); 317 + struct cxl_region_params *p = &cxlr->params; 318 + unsigned int val, save; 319 + int rc; 320 + u8 iw; 321 + 322 + rc = kstrtouint(buf, 0, &val); 323 + if (rc) 324 + return rc; 325 + 326 + rc = ways_to_cxl(val, &iw); 327 + if (rc) 328 + return rc; 329 + 330 + /* 331 + * Even for x3, x9, and x12 interleaves the region interleave must be a 332 + * power of 2 multiple of the host bridge interleave. 333 + */ 334 + if (!is_power_of_2(val / cxld->interleave_ways) || 335 + (val % cxld->interleave_ways)) { 336 + dev_dbg(&cxlr->dev, "invalid interleave: %d\n", val); 337 + return -EINVAL; 338 + } 339 + 340 + rc = down_write_killable(&cxl_region_rwsem); 341 + if (rc) 342 + return rc; 343 + if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 344 + rc = -EBUSY; 345 + goto out; 346 + } 347 + 348 + save = p->interleave_ways; 349 + p->interleave_ways = val; 350 + rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_target_group()); 351 + if (rc) 352 + p->interleave_ways = save; 353 + out: 354 + up_write(&cxl_region_rwsem); 355 + if (rc) 356 + return rc; 357 + return len; 358 + } 359 + static DEVICE_ATTR_RW(interleave_ways); 360 + 361 + static ssize_t interleave_granularity_show(struct device *dev, 362 + struct device_attribute *attr, 363 + char *buf) 364 + { 365 + struct cxl_region *cxlr = to_cxl_region(dev); 366 + struct cxl_region_params *p = &cxlr->params; 367 + ssize_t rc; 368 + 369 + rc = down_read_interruptible(&cxl_region_rwsem); 370 + if (rc) 371 + return rc; 372 + rc = sysfs_emit(buf, "%d\n", p->interleave_granularity); 373 + up_read(&cxl_region_rwsem); 374 + 375 + return rc; 376 + } 377 + 378 + static ssize_t interleave_granularity_store(struct device *dev, 379 + struct device_attribute *attr, 380 + const char *buf, size_t len) 381 + { 382 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev->parent); 383 + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 384 + struct cxl_region *cxlr = to_cxl_region(dev); 385 + struct cxl_region_params *p = &cxlr->params; 386 + int rc, val; 387 + u16 ig; 388 + 389 + rc = kstrtoint(buf, 0, &val); 390 + if (rc) 391 + return rc; 392 + 393 + rc = granularity_to_cxl(val, &ig); 394 + if (rc) 395 + return rc; 396 + 397 + /* 398 + * When the host-bridge is interleaved, disallow region granularity != 399 + * root granularity. Regions with a granularity less than the root 400 + * interleave result in needing multiple endpoints to support a single 401 + * slot in the interleave (possible to suport in the future). Regions 402 + * with a granularity greater than the root interleave result in invalid 403 + * DPA translations (invalid to support). 404 + */ 405 + if (cxld->interleave_ways > 1 && val != cxld->interleave_granularity) 406 + return -EINVAL; 407 + 408 + rc = down_write_killable(&cxl_region_rwsem); 409 + if (rc) 410 + return rc; 411 + if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) { 412 + rc = -EBUSY; 413 + goto out; 414 + } 415 + 416 + p->interleave_granularity = val; 417 + out: 418 + up_write(&cxl_region_rwsem); 419 + if (rc) 420 + return rc; 421 + return len; 422 + } 423 + static DEVICE_ATTR_RW(interleave_granularity); 424 + 425 + static ssize_t resource_show(struct device *dev, struct device_attribute *attr, 426 + char *buf) 427 + { 428 + struct cxl_region *cxlr = to_cxl_region(dev); 429 + struct cxl_region_params *p = &cxlr->params; 430 + u64 resource = -1ULL; 431 + ssize_t rc; 432 + 433 + rc = down_read_interruptible(&cxl_region_rwsem); 434 + if (rc) 435 + return rc; 436 + if (p->res) 437 + resource = p->res->start; 438 + rc = sysfs_emit(buf, "%#llx\n", resource); 439 + up_read(&cxl_region_rwsem); 440 + 441 + return rc; 442 + } 443 + static DEVICE_ATTR_RO(resource); 444 + 445 + static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) 446 + { 447 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); 448 + struct cxl_region_params *p = &cxlr->params; 449 + struct resource *res; 450 + u32 remainder = 0; 451 + 452 + lockdep_assert_held_write(&cxl_region_rwsem); 453 + 454 + /* Nothing to do... */ 455 + if (p->res && resource_size(p->res) == size) 456 + return 0; 457 + 458 + /* To change size the old size must be freed first */ 459 + if (p->res) 460 + return -EBUSY; 461 + 462 + if (p->state >= CXL_CONFIG_INTERLEAVE_ACTIVE) 463 + return -EBUSY; 464 + 465 + /* ways, granularity and uuid (if PMEM) need to be set before HPA */ 466 + if (!p->interleave_ways || !p->interleave_granularity || 467 + (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) 468 + return -ENXIO; 469 + 470 + div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder); 471 + if (remainder) 472 + return -EINVAL; 473 + 474 + res = alloc_free_mem_region(cxlrd->res, size, SZ_256M, 475 + dev_name(&cxlr->dev)); 476 + if (IS_ERR(res)) { 477 + dev_dbg(&cxlr->dev, "failed to allocate HPA: %ld\n", 478 + PTR_ERR(res)); 479 + return PTR_ERR(res); 480 + } 481 + 482 + p->res = res; 483 + p->state = CXL_CONFIG_INTERLEAVE_ACTIVE; 484 + 485 + return 0; 486 + } 487 + 488 + static void cxl_region_iomem_release(struct cxl_region *cxlr) 489 + { 490 + struct cxl_region_params *p = &cxlr->params; 491 + 492 + if (device_is_registered(&cxlr->dev)) 493 + lockdep_assert_held_write(&cxl_region_rwsem); 494 + if (p->res) { 495 + remove_resource(p->res); 496 + kfree(p->res); 497 + p->res = NULL; 498 + } 499 + } 500 + 501 + static int free_hpa(struct cxl_region *cxlr) 502 + { 503 + struct cxl_region_params *p = &cxlr->params; 504 + 505 + lockdep_assert_held_write(&cxl_region_rwsem); 506 + 507 + if (!p->res) 508 + return 0; 509 + 510 + if (p->state >= CXL_CONFIG_ACTIVE) 511 + return -EBUSY; 512 + 513 + cxl_region_iomem_release(cxlr); 514 + p->state = CXL_CONFIG_IDLE; 515 + return 0; 516 + } 517 + 518 + static ssize_t size_store(struct device *dev, struct device_attribute *attr, 519 + const char *buf, size_t len) 520 + { 521 + struct cxl_region *cxlr = to_cxl_region(dev); 522 + u64 val; 523 + int rc; 524 + 525 + rc = kstrtou64(buf, 0, &val); 526 + if (rc) 527 + return rc; 528 + 529 + rc = down_write_killable(&cxl_region_rwsem); 530 + if (rc) 531 + return rc; 532 + 533 + if (val) 534 + rc = alloc_hpa(cxlr, val); 535 + else 536 + rc = free_hpa(cxlr); 537 + up_write(&cxl_region_rwsem); 538 + 539 + if (rc) 540 + return rc; 541 + 542 + return len; 543 + } 544 + 545 + static ssize_t size_show(struct device *dev, struct device_attribute *attr, 546 + char *buf) 547 + { 548 + struct cxl_region *cxlr = to_cxl_region(dev); 549 + struct cxl_region_params *p = &cxlr->params; 550 + u64 size = 0; 551 + ssize_t rc; 552 + 553 + rc = down_read_interruptible(&cxl_region_rwsem); 554 + if (rc) 555 + return rc; 556 + if (p->res) 557 + size = resource_size(p->res); 558 + rc = sysfs_emit(buf, "%#llx\n", size); 559 + up_read(&cxl_region_rwsem); 560 + 561 + return rc; 562 + } 563 + static DEVICE_ATTR_RW(size); 564 + 565 + static struct attribute *cxl_region_attrs[] = { 566 + &dev_attr_uuid.attr, 567 + &dev_attr_commit.attr, 568 + &dev_attr_interleave_ways.attr, 569 + &dev_attr_interleave_granularity.attr, 570 + &dev_attr_resource.attr, 571 + &dev_attr_size.attr, 572 + NULL, 573 + }; 574 + 575 + static const struct attribute_group cxl_region_group = { 576 + .attrs = cxl_region_attrs, 577 + .is_visible = cxl_region_visible, 578 + }; 579 + 580 + static size_t show_targetN(struct cxl_region *cxlr, char *buf, int pos) 581 + { 582 + struct cxl_region_params *p = &cxlr->params; 583 + struct cxl_endpoint_decoder *cxled; 584 + int rc; 585 + 586 + rc = down_read_interruptible(&cxl_region_rwsem); 587 + if (rc) 588 + return rc; 589 + 590 + if (pos >= p->interleave_ways) { 591 + dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos, 592 + p->interleave_ways); 593 + rc = -ENXIO; 594 + goto out; 595 + } 596 + 597 + cxled = p->targets[pos]; 598 + if (!cxled) 599 + rc = sysfs_emit(buf, "\n"); 600 + else 601 + rc = sysfs_emit(buf, "%s\n", dev_name(&cxled->cxld.dev)); 602 + out: 603 + up_read(&cxl_region_rwsem); 604 + 605 + return rc; 606 + } 607 + 608 + static int match_free_decoder(struct device *dev, void *data) 609 + { 610 + struct cxl_decoder *cxld; 611 + int *id = data; 612 + 613 + if (!is_switch_decoder(dev)) 614 + return 0; 615 + 616 + cxld = to_cxl_decoder(dev); 617 + 618 + /* enforce ordered allocation */ 619 + if (cxld->id != *id) 620 + return 0; 621 + 622 + if (!cxld->region) 623 + return 1; 624 + 625 + (*id)++; 626 + 627 + return 0; 628 + } 629 + 630 + static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port, 631 + struct cxl_region *cxlr) 632 + { 633 + struct device *dev; 634 + int id = 0; 635 + 636 + dev = device_find_child(&port->dev, &id, match_free_decoder); 637 + if (!dev) 638 + return NULL; 639 + /* 640 + * This decoder is pinned registered as long as the endpoint decoder is 641 + * registered, and endpoint decoder unregistration holds the 642 + * cxl_region_rwsem over unregister events, so no need to hold on to 643 + * this extra reference. 644 + */ 645 + put_device(dev); 646 + return to_cxl_decoder(dev); 647 + } 648 + 649 + static struct cxl_region_ref *alloc_region_ref(struct cxl_port *port, 650 + struct cxl_region *cxlr) 651 + { 652 + struct cxl_region_params *p = &cxlr->params; 653 + struct cxl_region_ref *cxl_rr, *iter; 654 + unsigned long index; 655 + int rc; 656 + 657 + xa_for_each(&port->regions, index, iter) { 658 + struct cxl_region_params *ip = &iter->region->params; 659 + 660 + if (ip->res->start > p->res->start) { 661 + dev_dbg(&cxlr->dev, 662 + "%s: HPA order violation %s:%pr vs %pr\n", 663 + dev_name(&port->dev), 664 + dev_name(&iter->region->dev), ip->res, p->res); 665 + return ERR_PTR(-EBUSY); 666 + } 667 + } 668 + 669 + cxl_rr = kzalloc(sizeof(*cxl_rr), GFP_KERNEL); 670 + if (!cxl_rr) 671 + return ERR_PTR(-ENOMEM); 672 + cxl_rr->port = port; 673 + cxl_rr->region = cxlr; 674 + cxl_rr->nr_targets = 1; 675 + xa_init(&cxl_rr->endpoints); 676 + 677 + rc = xa_insert(&port->regions, (unsigned long)cxlr, cxl_rr, GFP_KERNEL); 678 + if (rc) { 679 + dev_dbg(&cxlr->dev, 680 + "%s: failed to track region reference: %d\n", 681 + dev_name(&port->dev), rc); 682 + kfree(cxl_rr); 683 + return ERR_PTR(rc); 684 + } 685 + 686 + return cxl_rr; 687 + } 688 + 689 + static void free_region_ref(struct cxl_region_ref *cxl_rr) 690 + { 691 + struct cxl_port *port = cxl_rr->port; 692 + struct cxl_region *cxlr = cxl_rr->region; 693 + struct cxl_decoder *cxld = cxl_rr->decoder; 694 + 695 + dev_WARN_ONCE(&cxlr->dev, cxld->region != cxlr, "region mismatch\n"); 696 + if (cxld->region == cxlr) { 697 + cxld->region = NULL; 698 + put_device(&cxlr->dev); 699 + } 700 + 701 + xa_erase(&port->regions, (unsigned long)cxlr); 702 + xa_destroy(&cxl_rr->endpoints); 703 + kfree(cxl_rr); 704 + } 705 + 706 + static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr, 707 + struct cxl_endpoint_decoder *cxled) 708 + { 709 + int rc; 710 + struct cxl_port *port = cxl_rr->port; 711 + struct cxl_region *cxlr = cxl_rr->region; 712 + struct cxl_decoder *cxld = cxl_rr->decoder; 713 + struct cxl_ep *ep = cxl_ep_load(port, cxled_to_memdev(cxled)); 714 + 715 + if (ep) { 716 + rc = xa_insert(&cxl_rr->endpoints, (unsigned long)cxled, ep, 717 + GFP_KERNEL); 718 + if (rc) 719 + return rc; 720 + } 721 + cxl_rr->nr_eps++; 722 + 723 + if (!cxld->region) { 724 + cxld->region = cxlr; 725 + get_device(&cxlr->dev); 726 + } 727 + 728 + return 0; 729 + } 730 + 731 + /** 732 + * cxl_port_attach_region() - track a region's interest in a port by endpoint 733 + * @port: port to add a new region reference 'struct cxl_region_ref' 734 + * @cxlr: region to attach to @port 735 + * @cxled: endpoint decoder used to create or further pin a region reference 736 + * @pos: interleave position of @cxled in @cxlr 737 + * 738 + * The attach event is an opportunity to validate CXL decode setup 739 + * constraints and record metadata needed for programming HDM decoders, 740 + * in particular decoder target lists. 741 + * 742 + * The steps are: 743 + * 744 + * - validate that there are no other regions with a higher HPA already 745 + * associated with @port 746 + * - establish a region reference if one is not already present 747 + * 748 + * - additionally allocate a decoder instance that will host @cxlr on 749 + * @port 750 + * 751 + * - pin the region reference by the endpoint 752 + * - account for how many entries in @port's target list are needed to 753 + * cover all of the added endpoints. 754 + */ 755 + static int cxl_port_attach_region(struct cxl_port *port, 756 + struct cxl_region *cxlr, 757 + struct cxl_endpoint_decoder *cxled, int pos) 758 + { 759 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 760 + struct cxl_ep *ep = cxl_ep_load(port, cxlmd); 761 + struct cxl_region_ref *cxl_rr; 762 + bool nr_targets_inc = false; 763 + struct cxl_decoder *cxld; 764 + unsigned long index; 765 + int rc = -EBUSY; 766 + 767 + lockdep_assert_held_write(&cxl_region_rwsem); 768 + 769 + cxl_rr = cxl_rr_load(port, cxlr); 770 + if (cxl_rr) { 771 + struct cxl_ep *ep_iter; 772 + int found = 0; 773 + 774 + /* 775 + * Walk the existing endpoints that have been attached to 776 + * @cxlr at @port and see if they share the same 'next' port 777 + * in the downstream direction. I.e. endpoints that share common 778 + * upstream switch. 779 + */ 780 + xa_for_each(&cxl_rr->endpoints, index, ep_iter) { 781 + if (ep_iter == ep) 782 + continue; 783 + if (ep_iter->next == ep->next) { 784 + found++; 785 + break; 786 + } 787 + } 788 + 789 + /* 790 + * New target port, or @port is an endpoint port that always 791 + * accounts its own local decode as a target. 792 + */ 793 + if (!found || !ep->next) { 794 + cxl_rr->nr_targets++; 795 + nr_targets_inc = true; 796 + } 797 + 798 + /* 799 + * The decoder for @cxlr was allocated when the region was first 800 + * attached to @port. 801 + */ 802 + cxld = cxl_rr->decoder; 803 + } else { 804 + cxl_rr = alloc_region_ref(port, cxlr); 805 + if (IS_ERR(cxl_rr)) { 806 + dev_dbg(&cxlr->dev, 807 + "%s: failed to allocate region reference\n", 808 + dev_name(&port->dev)); 809 + return PTR_ERR(cxl_rr); 810 + } 811 + nr_targets_inc = true; 812 + 813 + if (port == cxled_to_port(cxled)) 814 + cxld = &cxled->cxld; 815 + else 816 + cxld = cxl_region_find_decoder(port, cxlr); 817 + if (!cxld) { 818 + dev_dbg(&cxlr->dev, "%s: no decoder available\n", 819 + dev_name(&port->dev)); 820 + goto out_erase; 821 + } 822 + 823 + if (cxld->region) { 824 + dev_dbg(&cxlr->dev, "%s: %s already attached to %s\n", 825 + dev_name(&port->dev), dev_name(&cxld->dev), 826 + dev_name(&cxld->region->dev)); 827 + rc = -EBUSY; 828 + goto out_erase; 829 + } 830 + 831 + cxl_rr->decoder = cxld; 832 + } 833 + 834 + rc = cxl_rr_ep_add(cxl_rr, cxled); 835 + if (rc) { 836 + dev_dbg(&cxlr->dev, 837 + "%s: failed to track endpoint %s:%s reference\n", 838 + dev_name(&port->dev), dev_name(&cxlmd->dev), 839 + dev_name(&cxld->dev)); 840 + goto out_erase; 841 + } 842 + 843 + dev_dbg(&cxlr->dev, 844 + "%s:%s %s add: %s:%s @ %d next: %s nr_eps: %d nr_targets: %d\n", 845 + dev_name(port->uport), dev_name(&port->dev), 846 + dev_name(&cxld->dev), dev_name(&cxlmd->dev), 847 + dev_name(&cxled->cxld.dev), pos, 848 + ep ? ep->next ? dev_name(ep->next->uport) : 849 + dev_name(&cxlmd->dev) : 850 + "none", 851 + cxl_rr->nr_eps, cxl_rr->nr_targets); 852 + 853 + return 0; 854 + out_erase: 855 + if (nr_targets_inc) 856 + cxl_rr->nr_targets--; 857 + if (cxl_rr->nr_eps == 0) 858 + free_region_ref(cxl_rr); 859 + return rc; 860 + } 861 + 862 + static void cxl_port_detach_region(struct cxl_port *port, 863 + struct cxl_region *cxlr, 864 + struct cxl_endpoint_decoder *cxled) 865 + { 866 + struct cxl_region_ref *cxl_rr; 867 + struct cxl_ep *ep = NULL; 868 + 869 + lockdep_assert_held_write(&cxl_region_rwsem); 870 + 871 + cxl_rr = cxl_rr_load(port, cxlr); 872 + if (!cxl_rr) 873 + return; 874 + 875 + /* 876 + * Endpoint ports do not carry cxl_ep references, and they 877 + * never target more than one endpoint by definition 878 + */ 879 + if (cxl_rr->decoder == &cxled->cxld) 880 + cxl_rr->nr_eps--; 881 + else 882 + ep = xa_erase(&cxl_rr->endpoints, (unsigned long)cxled); 883 + if (ep) { 884 + struct cxl_ep *ep_iter; 885 + unsigned long index; 886 + int found = 0; 887 + 888 + cxl_rr->nr_eps--; 889 + xa_for_each(&cxl_rr->endpoints, index, ep_iter) { 890 + if (ep_iter->next == ep->next) { 891 + found++; 892 + break; 893 + } 894 + } 895 + if (!found) 896 + cxl_rr->nr_targets--; 897 + } 898 + 899 + if (cxl_rr->nr_eps == 0) 900 + free_region_ref(cxl_rr); 901 + } 902 + 903 + static int check_last_peer(struct cxl_endpoint_decoder *cxled, 904 + struct cxl_ep *ep, struct cxl_region_ref *cxl_rr, 905 + int distance) 906 + { 907 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 908 + struct cxl_region *cxlr = cxl_rr->region; 909 + struct cxl_region_params *p = &cxlr->params; 910 + struct cxl_endpoint_decoder *cxled_peer; 911 + struct cxl_port *port = cxl_rr->port; 912 + struct cxl_memdev *cxlmd_peer; 913 + struct cxl_ep *ep_peer; 914 + int pos = cxled->pos; 915 + 916 + /* 917 + * If this position wants to share a dport with the last endpoint mapped 918 + * then that endpoint, at index 'position - distance', must also be 919 + * mapped by this dport. 920 + */ 921 + if (pos < distance) { 922 + dev_dbg(&cxlr->dev, "%s:%s: cannot host %s:%s at %d\n", 923 + dev_name(port->uport), dev_name(&port->dev), 924 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); 925 + return -ENXIO; 926 + } 927 + cxled_peer = p->targets[pos - distance]; 928 + cxlmd_peer = cxled_to_memdev(cxled_peer); 929 + ep_peer = cxl_ep_load(port, cxlmd_peer); 930 + if (ep->dport != ep_peer->dport) { 931 + dev_dbg(&cxlr->dev, 932 + "%s:%s: %s:%s pos %d mismatched peer %s:%s\n", 933 + dev_name(port->uport), dev_name(&port->dev), 934 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos, 935 + dev_name(&cxlmd_peer->dev), 936 + dev_name(&cxled_peer->cxld.dev)); 937 + return -ENXIO; 938 + } 939 + 940 + return 0; 941 + } 942 + 943 + static int cxl_port_setup_targets(struct cxl_port *port, 944 + struct cxl_region *cxlr, 945 + struct cxl_endpoint_decoder *cxled) 946 + { 947 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); 948 + int parent_iw, parent_ig, ig, iw, rc, inc = 0, pos = cxled->pos; 949 + struct cxl_port *parent_port = to_cxl_port(port->dev.parent); 950 + struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr); 951 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 952 + struct cxl_ep *ep = cxl_ep_load(port, cxlmd); 953 + struct cxl_region_params *p = &cxlr->params; 954 + struct cxl_decoder *cxld = cxl_rr->decoder; 955 + struct cxl_switch_decoder *cxlsd; 956 + u16 eig, peig; 957 + u8 eiw, peiw; 958 + 959 + /* 960 + * While root level decoders support x3, x6, x12, switch level 961 + * decoders only support powers of 2 up to x16. 962 + */ 963 + if (!is_power_of_2(cxl_rr->nr_targets)) { 964 + dev_dbg(&cxlr->dev, "%s:%s: invalid target count %d\n", 965 + dev_name(port->uport), dev_name(&port->dev), 966 + cxl_rr->nr_targets); 967 + return -EINVAL; 968 + } 969 + 970 + cxlsd = to_cxl_switch_decoder(&cxld->dev); 971 + if (cxl_rr->nr_targets_set) { 972 + int i, distance; 973 + 974 + distance = p->nr_targets / cxl_rr->nr_targets; 975 + for (i = 0; i < cxl_rr->nr_targets_set; i++) 976 + if (ep->dport == cxlsd->target[i]) { 977 + rc = check_last_peer(cxled, ep, cxl_rr, 978 + distance); 979 + if (rc) 980 + return rc; 981 + goto out_target_set; 982 + } 983 + goto add_target; 984 + } 985 + 986 + if (is_cxl_root(parent_port)) { 987 + parent_ig = cxlrd->cxlsd.cxld.interleave_granularity; 988 + parent_iw = cxlrd->cxlsd.cxld.interleave_ways; 989 + /* 990 + * For purposes of address bit routing, use power-of-2 math for 991 + * switch ports. 992 + */ 993 + if (!is_power_of_2(parent_iw)) 994 + parent_iw /= 3; 995 + } else { 996 + struct cxl_region_ref *parent_rr; 997 + struct cxl_decoder *parent_cxld; 998 + 999 + parent_rr = cxl_rr_load(parent_port, cxlr); 1000 + parent_cxld = parent_rr->decoder; 1001 + parent_ig = parent_cxld->interleave_granularity; 1002 + parent_iw = parent_cxld->interleave_ways; 1003 + } 1004 + 1005 + rc = granularity_to_cxl(parent_ig, &peig); 1006 + if (rc) { 1007 + dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n", 1008 + dev_name(parent_port->uport), 1009 + dev_name(&parent_port->dev), parent_ig); 1010 + return rc; 1011 + } 1012 + 1013 + rc = ways_to_cxl(parent_iw, &peiw); 1014 + if (rc) { 1015 + dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n", 1016 + dev_name(parent_port->uport), 1017 + dev_name(&parent_port->dev), parent_iw); 1018 + return rc; 1019 + } 1020 + 1021 + iw = cxl_rr->nr_targets; 1022 + rc = ways_to_cxl(iw, &eiw); 1023 + if (rc) { 1024 + dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n", 1025 + dev_name(port->uport), dev_name(&port->dev), iw); 1026 + return rc; 1027 + } 1028 + 1029 + /* 1030 + * If @parent_port is masking address bits, pick the next unused address 1031 + * bit to route @port's targets. 1032 + */ 1033 + if (parent_iw > 1 && cxl_rr->nr_targets > 1) { 1034 + u32 address_bit = max(peig + peiw, eiw + peig); 1035 + 1036 + eig = address_bit - eiw + 1; 1037 + } else { 1038 + eiw = peiw; 1039 + eig = peig; 1040 + } 1041 + 1042 + rc = cxl_to_granularity(eig, &ig); 1043 + if (rc) { 1044 + dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n", 1045 + dev_name(port->uport), dev_name(&port->dev), 1046 + 256 << eig); 1047 + return rc; 1048 + } 1049 + 1050 + cxld->interleave_ways = iw; 1051 + cxld->interleave_granularity = ig; 1052 + cxld->hpa_range = (struct range) { 1053 + .start = p->res->start, 1054 + .end = p->res->end, 1055 + }; 1056 + dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport), 1057 + dev_name(&port->dev), iw, ig); 1058 + add_target: 1059 + if (cxl_rr->nr_targets_set == cxl_rr->nr_targets) { 1060 + dev_dbg(&cxlr->dev, 1061 + "%s:%s: targets full trying to add %s:%s at %d\n", 1062 + dev_name(port->uport), dev_name(&port->dev), 1063 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); 1064 + return -ENXIO; 1065 + } 1066 + cxlsd->target[cxl_rr->nr_targets_set] = ep->dport; 1067 + inc = 1; 1068 + out_target_set: 1069 + cxl_rr->nr_targets_set += inc; 1070 + dev_dbg(&cxlr->dev, "%s:%s target[%d] = %s for %s:%s @ %d\n", 1071 + dev_name(port->uport), dev_name(&port->dev), 1072 + cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport), 1073 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); 1074 + 1075 + return 0; 1076 + } 1077 + 1078 + static void cxl_port_reset_targets(struct cxl_port *port, 1079 + struct cxl_region *cxlr) 1080 + { 1081 + struct cxl_region_ref *cxl_rr = cxl_rr_load(port, cxlr); 1082 + struct cxl_decoder *cxld; 1083 + 1084 + /* 1085 + * After the last endpoint has been detached the entire cxl_rr may now 1086 + * be gone. 1087 + */ 1088 + if (!cxl_rr) 1089 + return; 1090 + cxl_rr->nr_targets_set = 0; 1091 + 1092 + cxld = cxl_rr->decoder; 1093 + cxld->hpa_range = (struct range) { 1094 + .start = 0, 1095 + .end = -1, 1096 + }; 1097 + } 1098 + 1099 + static void cxl_region_teardown_targets(struct cxl_region *cxlr) 1100 + { 1101 + struct cxl_region_params *p = &cxlr->params; 1102 + struct cxl_endpoint_decoder *cxled; 1103 + struct cxl_memdev *cxlmd; 1104 + struct cxl_port *iter; 1105 + struct cxl_ep *ep; 1106 + int i; 1107 + 1108 + for (i = 0; i < p->nr_targets; i++) { 1109 + cxled = p->targets[i]; 1110 + cxlmd = cxled_to_memdev(cxled); 1111 + 1112 + iter = cxled_to_port(cxled); 1113 + while (!is_cxl_root(to_cxl_port(iter->dev.parent))) 1114 + iter = to_cxl_port(iter->dev.parent); 1115 + 1116 + for (ep = cxl_ep_load(iter, cxlmd); iter; 1117 + iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) 1118 + cxl_port_reset_targets(iter, cxlr); 1119 + } 1120 + } 1121 + 1122 + static int cxl_region_setup_targets(struct cxl_region *cxlr) 1123 + { 1124 + struct cxl_region_params *p = &cxlr->params; 1125 + struct cxl_endpoint_decoder *cxled; 1126 + struct cxl_memdev *cxlmd; 1127 + struct cxl_port *iter; 1128 + struct cxl_ep *ep; 1129 + int i, rc; 1130 + 1131 + for (i = 0; i < p->nr_targets; i++) { 1132 + cxled = p->targets[i]; 1133 + cxlmd = cxled_to_memdev(cxled); 1134 + 1135 + iter = cxled_to_port(cxled); 1136 + while (!is_cxl_root(to_cxl_port(iter->dev.parent))) 1137 + iter = to_cxl_port(iter->dev.parent); 1138 + 1139 + /* 1140 + * Descend the topology tree programming targets while 1141 + * looking for conflicts. 1142 + */ 1143 + for (ep = cxl_ep_load(iter, cxlmd); iter; 1144 + iter = ep->next, ep = cxl_ep_load(iter, cxlmd)) { 1145 + rc = cxl_port_setup_targets(iter, cxlr, cxled); 1146 + if (rc) { 1147 + cxl_region_teardown_targets(cxlr); 1148 + return rc; 1149 + } 1150 + } 1151 + } 1152 + 1153 + return 0; 1154 + } 1155 + 1156 + static int cxl_region_attach(struct cxl_region *cxlr, 1157 + struct cxl_endpoint_decoder *cxled, int pos) 1158 + { 1159 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); 1160 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 1161 + struct cxl_port *ep_port, *root_port, *iter; 1162 + struct cxl_region_params *p = &cxlr->params; 1163 + struct cxl_dport *dport; 1164 + int i, rc = -ENXIO; 1165 + 1166 + if (cxled->mode == CXL_DECODER_DEAD) { 1167 + dev_dbg(&cxlr->dev, "%s dead\n", dev_name(&cxled->cxld.dev)); 1168 + return -ENODEV; 1169 + } 1170 + 1171 + /* all full of members, or interleave config not established? */ 1172 + if (p->state > CXL_CONFIG_INTERLEAVE_ACTIVE) { 1173 + dev_dbg(&cxlr->dev, "region already active\n"); 1174 + return -EBUSY; 1175 + } else if (p->state < CXL_CONFIG_INTERLEAVE_ACTIVE) { 1176 + dev_dbg(&cxlr->dev, "interleave config missing\n"); 1177 + return -ENXIO; 1178 + } 1179 + 1180 + if (pos < 0 || pos >= p->interleave_ways) { 1181 + dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos, 1182 + p->interleave_ways); 1183 + return -ENXIO; 1184 + } 1185 + 1186 + if (p->targets[pos] == cxled) 1187 + return 0; 1188 + 1189 + if (p->targets[pos]) { 1190 + struct cxl_endpoint_decoder *cxled_target = p->targets[pos]; 1191 + struct cxl_memdev *cxlmd_target = cxled_to_memdev(cxled_target); 1192 + 1193 + dev_dbg(&cxlr->dev, "position %d already assigned to %s:%s\n", 1194 + pos, dev_name(&cxlmd_target->dev), 1195 + dev_name(&cxled_target->cxld.dev)); 1196 + return -EBUSY; 1197 + } 1198 + 1199 + for (i = 0; i < p->interleave_ways; i++) { 1200 + struct cxl_endpoint_decoder *cxled_target; 1201 + struct cxl_memdev *cxlmd_target; 1202 + 1203 + cxled_target = p->targets[pos]; 1204 + if (!cxled_target) 1205 + continue; 1206 + 1207 + cxlmd_target = cxled_to_memdev(cxled_target); 1208 + if (cxlmd_target == cxlmd) { 1209 + dev_dbg(&cxlr->dev, 1210 + "%s already specified at position %d via: %s\n", 1211 + dev_name(&cxlmd->dev), pos, 1212 + dev_name(&cxled_target->cxld.dev)); 1213 + return -EBUSY; 1214 + } 1215 + } 1216 + 1217 + ep_port = cxled_to_port(cxled); 1218 + root_port = cxlrd_to_port(cxlrd); 1219 + dport = cxl_find_dport_by_dev(root_port, ep_port->host_bridge); 1220 + if (!dport) { 1221 + dev_dbg(&cxlr->dev, "%s:%s invalid target for %s\n", 1222 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1223 + dev_name(cxlr->dev.parent)); 1224 + return -ENXIO; 1225 + } 1226 + 1227 + if (cxlrd->calc_hb(cxlrd, pos) != dport) { 1228 + dev_dbg(&cxlr->dev, "%s:%s invalid target position for %s\n", 1229 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1230 + dev_name(&cxlrd->cxlsd.cxld.dev)); 1231 + return -ENXIO; 1232 + } 1233 + 1234 + if (cxled->cxld.target_type != cxlr->type) { 1235 + dev_dbg(&cxlr->dev, "%s:%s type mismatch: %d vs %d\n", 1236 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1237 + cxled->cxld.target_type, cxlr->type); 1238 + return -ENXIO; 1239 + } 1240 + 1241 + if (!cxled->dpa_res) { 1242 + dev_dbg(&cxlr->dev, "%s:%s: missing DPA allocation.\n", 1243 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev)); 1244 + return -ENXIO; 1245 + } 1246 + 1247 + if (resource_size(cxled->dpa_res) * p->interleave_ways != 1248 + resource_size(p->res)) { 1249 + dev_dbg(&cxlr->dev, 1250 + "%s:%s: decoder-size-%#llx * ways-%d != region-size-%#llx\n", 1251 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1252 + (u64)resource_size(cxled->dpa_res), p->interleave_ways, 1253 + (u64)resource_size(p->res)); 1254 + return -EINVAL; 1255 + } 1256 + 1257 + for (iter = ep_port; !is_cxl_root(iter); 1258 + iter = to_cxl_port(iter->dev.parent)) { 1259 + rc = cxl_port_attach_region(iter, cxlr, cxled, pos); 1260 + if (rc) 1261 + goto err; 1262 + } 1263 + 1264 + p->targets[pos] = cxled; 1265 + cxled->pos = pos; 1266 + p->nr_targets++; 1267 + 1268 + if (p->nr_targets == p->interleave_ways) { 1269 + rc = cxl_region_setup_targets(cxlr); 1270 + if (rc) 1271 + goto err_decrement; 1272 + p->state = CXL_CONFIG_ACTIVE; 1273 + } 1274 + 1275 + cxled->cxld.interleave_ways = p->interleave_ways; 1276 + cxled->cxld.interleave_granularity = p->interleave_granularity; 1277 + cxled->cxld.hpa_range = (struct range) { 1278 + .start = p->res->start, 1279 + .end = p->res->end, 1280 + }; 1281 + 1282 + return 0; 1283 + 1284 + err_decrement: 1285 + p->nr_targets--; 1286 + err: 1287 + for (iter = ep_port; !is_cxl_root(iter); 1288 + iter = to_cxl_port(iter->dev.parent)) 1289 + cxl_port_detach_region(iter, cxlr, cxled); 1290 + return rc; 1291 + } 1292 + 1293 + static int cxl_region_detach(struct cxl_endpoint_decoder *cxled) 1294 + { 1295 + struct cxl_port *iter, *ep_port = cxled_to_port(cxled); 1296 + struct cxl_region *cxlr = cxled->cxld.region; 1297 + struct cxl_region_params *p; 1298 + int rc = 0; 1299 + 1300 + lockdep_assert_held_write(&cxl_region_rwsem); 1301 + 1302 + if (!cxlr) 1303 + return 0; 1304 + 1305 + p = &cxlr->params; 1306 + get_device(&cxlr->dev); 1307 + 1308 + if (p->state > CXL_CONFIG_ACTIVE) { 1309 + /* 1310 + * TODO: tear down all impacted regions if a device is 1311 + * removed out of order 1312 + */ 1313 + rc = cxl_region_decode_reset(cxlr, p->interleave_ways); 1314 + if (rc) 1315 + goto out; 1316 + p->state = CXL_CONFIG_ACTIVE; 1317 + } 1318 + 1319 + for (iter = ep_port; !is_cxl_root(iter); 1320 + iter = to_cxl_port(iter->dev.parent)) 1321 + cxl_port_detach_region(iter, cxlr, cxled); 1322 + 1323 + if (cxled->pos < 0 || cxled->pos >= p->interleave_ways || 1324 + p->targets[cxled->pos] != cxled) { 1325 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 1326 + 1327 + dev_WARN_ONCE(&cxlr->dev, 1, "expected %s:%s at position %d\n", 1328 + dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), 1329 + cxled->pos); 1330 + goto out; 1331 + } 1332 + 1333 + if (p->state == CXL_CONFIG_ACTIVE) { 1334 + p->state = CXL_CONFIG_INTERLEAVE_ACTIVE; 1335 + cxl_region_teardown_targets(cxlr); 1336 + } 1337 + p->targets[cxled->pos] = NULL; 1338 + p->nr_targets--; 1339 + cxled->cxld.hpa_range = (struct range) { 1340 + .start = 0, 1341 + .end = -1, 1342 + }; 1343 + 1344 + /* notify the region driver that one of its targets has departed */ 1345 + up_write(&cxl_region_rwsem); 1346 + device_release_driver(&cxlr->dev); 1347 + down_write(&cxl_region_rwsem); 1348 + out: 1349 + put_device(&cxlr->dev); 1350 + return rc; 1351 + } 1352 + 1353 + void cxl_decoder_kill_region(struct cxl_endpoint_decoder *cxled) 1354 + { 1355 + down_write(&cxl_region_rwsem); 1356 + cxled->mode = CXL_DECODER_DEAD; 1357 + cxl_region_detach(cxled); 1358 + up_write(&cxl_region_rwsem); 1359 + } 1360 + 1361 + static int attach_target(struct cxl_region *cxlr, const char *decoder, int pos) 1362 + { 1363 + struct device *dev; 1364 + int rc; 1365 + 1366 + dev = bus_find_device_by_name(&cxl_bus_type, NULL, decoder); 1367 + if (!dev) 1368 + return -ENODEV; 1369 + 1370 + if (!is_endpoint_decoder(dev)) { 1371 + put_device(dev); 1372 + return -EINVAL; 1373 + } 1374 + 1375 + rc = down_write_killable(&cxl_region_rwsem); 1376 + if (rc) 1377 + goto out; 1378 + down_read(&cxl_dpa_rwsem); 1379 + rc = cxl_region_attach(cxlr, to_cxl_endpoint_decoder(dev), pos); 1380 + up_read(&cxl_dpa_rwsem); 1381 + up_write(&cxl_region_rwsem); 1382 + out: 1383 + put_device(dev); 1384 + return rc; 1385 + } 1386 + 1387 + static int detach_target(struct cxl_region *cxlr, int pos) 1388 + { 1389 + struct cxl_region_params *p = &cxlr->params; 1390 + int rc; 1391 + 1392 + rc = down_write_killable(&cxl_region_rwsem); 1393 + if (rc) 1394 + return rc; 1395 + 1396 + if (pos >= p->interleave_ways) { 1397 + dev_dbg(&cxlr->dev, "position %d out of range %d\n", pos, 1398 + p->interleave_ways); 1399 + rc = -ENXIO; 1400 + goto out; 1401 + } 1402 + 1403 + if (!p->targets[pos]) { 1404 + rc = 0; 1405 + goto out; 1406 + } 1407 + 1408 + rc = cxl_region_detach(p->targets[pos]); 1409 + out: 1410 + up_write(&cxl_region_rwsem); 1411 + return rc; 1412 + } 1413 + 1414 + static size_t store_targetN(struct cxl_region *cxlr, const char *buf, int pos, 1415 + size_t len) 1416 + { 1417 + int rc; 1418 + 1419 + if (sysfs_streq(buf, "\n")) 1420 + rc = detach_target(cxlr, pos); 1421 + else 1422 + rc = attach_target(cxlr, buf, pos); 1423 + 1424 + if (rc < 0) 1425 + return rc; 1426 + return len; 1427 + } 1428 + 1429 + #define TARGET_ATTR_RW(n) \ 1430 + static ssize_t target##n##_show( \ 1431 + struct device *dev, struct device_attribute *attr, char *buf) \ 1432 + { \ 1433 + return show_targetN(to_cxl_region(dev), buf, (n)); \ 1434 + } \ 1435 + static ssize_t target##n##_store(struct device *dev, \ 1436 + struct device_attribute *attr, \ 1437 + const char *buf, size_t len) \ 1438 + { \ 1439 + return store_targetN(to_cxl_region(dev), buf, (n), len); \ 1440 + } \ 1441 + static DEVICE_ATTR_RW(target##n) 1442 + 1443 + TARGET_ATTR_RW(0); 1444 + TARGET_ATTR_RW(1); 1445 + TARGET_ATTR_RW(2); 1446 + TARGET_ATTR_RW(3); 1447 + TARGET_ATTR_RW(4); 1448 + TARGET_ATTR_RW(5); 1449 + TARGET_ATTR_RW(6); 1450 + TARGET_ATTR_RW(7); 1451 + TARGET_ATTR_RW(8); 1452 + TARGET_ATTR_RW(9); 1453 + TARGET_ATTR_RW(10); 1454 + TARGET_ATTR_RW(11); 1455 + TARGET_ATTR_RW(12); 1456 + TARGET_ATTR_RW(13); 1457 + TARGET_ATTR_RW(14); 1458 + TARGET_ATTR_RW(15); 1459 + 1460 + static struct attribute *target_attrs[] = { 1461 + &dev_attr_target0.attr, 1462 + &dev_attr_target1.attr, 1463 + &dev_attr_target2.attr, 1464 + &dev_attr_target3.attr, 1465 + &dev_attr_target4.attr, 1466 + &dev_attr_target5.attr, 1467 + &dev_attr_target6.attr, 1468 + &dev_attr_target7.attr, 1469 + &dev_attr_target8.attr, 1470 + &dev_attr_target9.attr, 1471 + &dev_attr_target10.attr, 1472 + &dev_attr_target11.attr, 1473 + &dev_attr_target12.attr, 1474 + &dev_attr_target13.attr, 1475 + &dev_attr_target14.attr, 1476 + &dev_attr_target15.attr, 1477 + NULL, 1478 + }; 1479 + 1480 + static umode_t cxl_region_target_visible(struct kobject *kobj, 1481 + struct attribute *a, int n) 1482 + { 1483 + struct device *dev = kobj_to_dev(kobj); 1484 + struct cxl_region *cxlr = to_cxl_region(dev); 1485 + struct cxl_region_params *p = &cxlr->params; 1486 + 1487 + if (n < p->interleave_ways) 1488 + return a->mode; 1489 + return 0; 1490 + } 1491 + 1492 + static const struct attribute_group cxl_region_target_group = { 1493 + .attrs = target_attrs, 1494 + .is_visible = cxl_region_target_visible, 1495 + }; 1496 + 1497 + static const struct attribute_group *get_cxl_region_target_group(void) 1498 + { 1499 + return &cxl_region_target_group; 1500 + } 1501 + 1502 + static const struct attribute_group *region_groups[] = { 1503 + &cxl_base_attribute_group, 1504 + &cxl_region_group, 1505 + &cxl_region_target_group, 1506 + NULL, 1507 + }; 1508 + 1509 + static void cxl_region_release(struct device *dev) 1510 + { 1511 + struct cxl_region *cxlr = to_cxl_region(dev); 1512 + 1513 + memregion_free(cxlr->id); 1514 + kfree(cxlr); 1515 + } 1516 + 1517 + const struct device_type cxl_region_type = { 1518 + .name = "cxl_region", 1519 + .release = cxl_region_release, 1520 + .groups = region_groups 1521 + }; 1522 + 1523 + bool is_cxl_region(struct device *dev) 1524 + { 1525 + return dev->type == &cxl_region_type; 1526 + } 1527 + EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL); 1528 + 1529 + static struct cxl_region *to_cxl_region(struct device *dev) 1530 + { 1531 + if (dev_WARN_ONCE(dev, dev->type != &cxl_region_type, 1532 + "not a cxl_region device\n")) 1533 + return NULL; 1534 + 1535 + return container_of(dev, struct cxl_region, dev); 1536 + } 1537 + 1538 + static void unregister_region(void *dev) 1539 + { 1540 + struct cxl_region *cxlr = to_cxl_region(dev); 1541 + 1542 + device_del(dev); 1543 + cxl_region_iomem_release(cxlr); 1544 + put_device(dev); 1545 + } 1546 + 1547 + static struct lock_class_key cxl_region_key; 1548 + 1549 + static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int id) 1550 + { 1551 + struct cxl_region *cxlr; 1552 + struct device *dev; 1553 + 1554 + cxlr = kzalloc(sizeof(*cxlr), GFP_KERNEL); 1555 + if (!cxlr) { 1556 + memregion_free(id); 1557 + return ERR_PTR(-ENOMEM); 1558 + } 1559 + 1560 + dev = &cxlr->dev; 1561 + device_initialize(dev); 1562 + lockdep_set_class(&dev->mutex, &cxl_region_key); 1563 + dev->parent = &cxlrd->cxlsd.cxld.dev; 1564 + device_set_pm_not_required(dev); 1565 + dev->bus = &cxl_bus_type; 1566 + dev->type = &cxl_region_type; 1567 + cxlr->id = id; 1568 + 1569 + return cxlr; 1570 + } 1571 + 1572 + /** 1573 + * devm_cxl_add_region - Adds a region to a decoder 1574 + * @cxlrd: root decoder 1575 + * @id: memregion id to create, or memregion_free() on failure 1576 + * @mode: mode for the endpoint decoders of this region 1577 + * @type: select whether this is an expander or accelerator (type-2 or type-3) 1578 + * 1579 + * This is the second step of region initialization. Regions exist within an 1580 + * address space which is mapped by a @cxlrd. 1581 + * 1582 + * Return: 0 if the region was added to the @cxlrd, else returns negative error 1583 + * code. The region will be named "regionZ" where Z is the unique region number. 1584 + */ 1585 + static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, 1586 + int id, 1587 + enum cxl_decoder_mode mode, 1588 + enum cxl_decoder_type type) 1589 + { 1590 + struct cxl_port *port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent); 1591 + struct cxl_region *cxlr; 1592 + struct device *dev; 1593 + int rc; 1594 + 1595 + cxlr = cxl_region_alloc(cxlrd, id); 1596 + if (IS_ERR(cxlr)) 1597 + return cxlr; 1598 + cxlr->mode = mode; 1599 + cxlr->type = type; 1600 + 1601 + dev = &cxlr->dev; 1602 + rc = dev_set_name(dev, "region%d", id); 1603 + if (rc) 1604 + goto err; 1605 + 1606 + rc = device_add(dev); 1607 + if (rc) 1608 + goto err; 1609 + 1610 + rc = devm_add_action_or_reset(port->uport, unregister_region, cxlr); 1611 + if (rc) 1612 + return ERR_PTR(rc); 1613 + 1614 + dev_dbg(port->uport, "%s: created %s\n", 1615 + dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev)); 1616 + return cxlr; 1617 + 1618 + err: 1619 + put_device(dev); 1620 + return ERR_PTR(rc); 1621 + } 1622 + 1623 + static ssize_t create_pmem_region_show(struct device *dev, 1624 + struct device_attribute *attr, char *buf) 1625 + { 1626 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 1627 + 1628 + return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id)); 1629 + } 1630 + 1631 + static ssize_t create_pmem_region_store(struct device *dev, 1632 + struct device_attribute *attr, 1633 + const char *buf, size_t len) 1634 + { 1635 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 1636 + struct cxl_region *cxlr; 1637 + int id, rc; 1638 + 1639 + rc = sscanf(buf, "region%d\n", &id); 1640 + if (rc != 1) 1641 + return -EINVAL; 1642 + 1643 + rc = memregion_alloc(GFP_KERNEL); 1644 + if (rc < 0) 1645 + return rc; 1646 + 1647 + if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) { 1648 + memregion_free(rc); 1649 + return -EBUSY; 1650 + } 1651 + 1652 + cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM, 1653 + CXL_DECODER_EXPANDER); 1654 + if (IS_ERR(cxlr)) 1655 + return PTR_ERR(cxlr); 1656 + 1657 + return len; 1658 + } 1659 + DEVICE_ATTR_RW(create_pmem_region); 1660 + 1661 + static ssize_t region_show(struct device *dev, struct device_attribute *attr, 1662 + char *buf) 1663 + { 1664 + struct cxl_decoder *cxld = to_cxl_decoder(dev); 1665 + ssize_t rc; 1666 + 1667 + rc = down_read_interruptible(&cxl_region_rwsem); 1668 + if (rc) 1669 + return rc; 1670 + 1671 + if (cxld->region) 1672 + rc = sysfs_emit(buf, "%s\n", dev_name(&cxld->region->dev)); 1673 + else 1674 + rc = sysfs_emit(buf, "\n"); 1675 + up_read(&cxl_region_rwsem); 1676 + 1677 + return rc; 1678 + } 1679 + DEVICE_ATTR_RO(region); 1680 + 1681 + static struct cxl_region * 1682 + cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name) 1683 + { 1684 + struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 1685 + struct device *region_dev; 1686 + 1687 + region_dev = device_find_child_by_name(&cxld->dev, name); 1688 + if (!region_dev) 1689 + return ERR_PTR(-ENODEV); 1690 + 1691 + return to_cxl_region(region_dev); 1692 + } 1693 + 1694 + static ssize_t delete_region_store(struct device *dev, 1695 + struct device_attribute *attr, 1696 + const char *buf, size_t len) 1697 + { 1698 + struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 1699 + struct cxl_port *port = to_cxl_port(dev->parent); 1700 + struct cxl_region *cxlr; 1701 + 1702 + cxlr = cxl_find_region_by_name(cxlrd, buf); 1703 + if (IS_ERR(cxlr)) 1704 + return PTR_ERR(cxlr); 1705 + 1706 + devm_release_action(port->uport, unregister_region, cxlr); 1707 + put_device(&cxlr->dev); 1708 + 1709 + return len; 1710 + } 1711 + DEVICE_ATTR_WO(delete_region); 1712 + 1713 + static void cxl_pmem_region_release(struct device *dev) 1714 + { 1715 + struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev); 1716 + int i; 1717 + 1718 + for (i = 0; i < cxlr_pmem->nr_mappings; i++) { 1719 + struct cxl_memdev *cxlmd = cxlr_pmem->mapping[i].cxlmd; 1720 + 1721 + put_device(&cxlmd->dev); 1722 + } 1723 + 1724 + kfree(cxlr_pmem); 1725 + } 1726 + 1727 + static const struct attribute_group *cxl_pmem_region_attribute_groups[] = { 1728 + &cxl_base_attribute_group, 1729 + NULL, 1730 + }; 1731 + 1732 + const struct device_type cxl_pmem_region_type = { 1733 + .name = "cxl_pmem_region", 1734 + .release = cxl_pmem_region_release, 1735 + .groups = cxl_pmem_region_attribute_groups, 1736 + }; 1737 + 1738 + bool is_cxl_pmem_region(struct device *dev) 1739 + { 1740 + return dev->type == &cxl_pmem_region_type; 1741 + } 1742 + EXPORT_SYMBOL_NS_GPL(is_cxl_pmem_region, CXL); 1743 + 1744 + struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev) 1745 + { 1746 + if (dev_WARN_ONCE(dev, !is_cxl_pmem_region(dev), 1747 + "not a cxl_pmem_region device\n")) 1748 + return NULL; 1749 + return container_of(dev, struct cxl_pmem_region, dev); 1750 + } 1751 + EXPORT_SYMBOL_NS_GPL(to_cxl_pmem_region, CXL); 1752 + 1753 + static struct lock_class_key cxl_pmem_region_key; 1754 + 1755 + static struct cxl_pmem_region *cxl_pmem_region_alloc(struct cxl_region *cxlr) 1756 + { 1757 + struct cxl_region_params *p = &cxlr->params; 1758 + struct cxl_pmem_region *cxlr_pmem; 1759 + struct device *dev; 1760 + int i; 1761 + 1762 + down_read(&cxl_region_rwsem); 1763 + if (p->state != CXL_CONFIG_COMMIT) { 1764 + cxlr_pmem = ERR_PTR(-ENXIO); 1765 + goto out; 1766 + } 1767 + 1768 + cxlr_pmem = kzalloc(struct_size(cxlr_pmem, mapping, p->nr_targets), 1769 + GFP_KERNEL); 1770 + if (!cxlr_pmem) { 1771 + cxlr_pmem = ERR_PTR(-ENOMEM); 1772 + goto out; 1773 + } 1774 + 1775 + cxlr_pmem->hpa_range.start = p->res->start; 1776 + cxlr_pmem->hpa_range.end = p->res->end; 1777 + 1778 + /* Snapshot the region configuration underneath the cxl_region_rwsem */ 1779 + cxlr_pmem->nr_mappings = p->nr_targets; 1780 + for (i = 0; i < p->nr_targets; i++) { 1781 + struct cxl_endpoint_decoder *cxled = p->targets[i]; 1782 + struct cxl_memdev *cxlmd = cxled_to_memdev(cxled); 1783 + struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i]; 1784 + 1785 + m->cxlmd = cxlmd; 1786 + get_device(&cxlmd->dev); 1787 + m->start = cxled->dpa_res->start; 1788 + m->size = resource_size(cxled->dpa_res); 1789 + m->position = i; 1790 + } 1791 + 1792 + dev = &cxlr_pmem->dev; 1793 + cxlr_pmem->cxlr = cxlr; 1794 + device_initialize(dev); 1795 + lockdep_set_class(&dev->mutex, &cxl_pmem_region_key); 1796 + device_set_pm_not_required(dev); 1797 + dev->parent = &cxlr->dev; 1798 + dev->bus = &cxl_bus_type; 1799 + dev->type = &cxl_pmem_region_type; 1800 + out: 1801 + up_read(&cxl_region_rwsem); 1802 + 1803 + return cxlr_pmem; 1804 + } 1805 + 1806 + static void cxlr_pmem_unregister(void *dev) 1807 + { 1808 + device_unregister(dev); 1809 + } 1810 + 1811 + /** 1812 + * devm_cxl_add_pmem_region() - add a cxl_region-to-nd_region bridge 1813 + * @cxlr: parent CXL region for this pmem region bridge device 1814 + * 1815 + * Return: 0 on success negative error code on failure. 1816 + */ 1817 + static int devm_cxl_add_pmem_region(struct cxl_region *cxlr) 1818 + { 1819 + struct cxl_pmem_region *cxlr_pmem; 1820 + struct device *dev; 1821 + int rc; 1822 + 1823 + cxlr_pmem = cxl_pmem_region_alloc(cxlr); 1824 + if (IS_ERR(cxlr_pmem)) 1825 + return PTR_ERR(cxlr_pmem); 1826 + 1827 + dev = &cxlr_pmem->dev; 1828 + rc = dev_set_name(dev, "pmem_region%d", cxlr->id); 1829 + if (rc) 1830 + goto err; 1831 + 1832 + rc = device_add(dev); 1833 + if (rc) 1834 + goto err; 1835 + 1836 + dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent), 1837 + dev_name(dev)); 1838 + 1839 + return devm_add_action_or_reset(&cxlr->dev, cxlr_pmem_unregister, dev); 1840 + 1841 + err: 1842 + put_device(dev); 1843 + return rc; 1844 + } 1845 + 1846 + static int cxl_region_probe(struct device *dev) 1847 + { 1848 + struct cxl_region *cxlr = to_cxl_region(dev); 1849 + struct cxl_region_params *p = &cxlr->params; 1850 + int rc; 1851 + 1852 + rc = down_read_interruptible(&cxl_region_rwsem); 1853 + if (rc) { 1854 + dev_dbg(&cxlr->dev, "probe interrupted\n"); 1855 + return rc; 1856 + } 1857 + 1858 + if (p->state < CXL_CONFIG_COMMIT) { 1859 + dev_dbg(&cxlr->dev, "config state: %d\n", p->state); 1860 + rc = -ENXIO; 1861 + } 1862 + 1863 + /* 1864 + * From this point on any path that changes the region's state away from 1865 + * CXL_CONFIG_COMMIT is also responsible for releasing the driver. 1866 + */ 1867 + up_read(&cxl_region_rwsem); 1868 + 1869 + switch (cxlr->mode) { 1870 + case CXL_DECODER_PMEM: 1871 + return devm_cxl_add_pmem_region(cxlr); 1872 + default: 1873 + dev_dbg(&cxlr->dev, "unsupported region mode: %d\n", 1874 + cxlr->mode); 1875 + return -ENXIO; 1876 + } 1877 + } 1878 + 1879 + static struct cxl_driver cxl_region_driver = { 1880 + .name = "cxl_region", 1881 + .probe = cxl_region_probe, 1882 + .id = CXL_DEVICE_REGION, 1883 + }; 1884 + 1885 + int cxl_region_init(void) 1886 + { 1887 + return cxl_driver_register(&cxl_region_driver); 1888 + } 1889 + 1890 + void cxl_region_exit(void) 1891 + { 1892 + cxl_driver_unregister(&cxl_region_driver); 1893 + } 1894 + 1895 + MODULE_IMPORT_NS(CXL); 1896 + MODULE_ALIAS_CXL(CXL_DEVICE_REGION);
+283 -29
drivers/cxl/cxl.h
··· 7 7 #include <linux/libnvdimm.h> 8 8 #include <linux/bitfield.h> 9 9 #include <linux/bitops.h> 10 + #include <linux/log2.h> 10 11 #include <linux/io.h> 11 12 12 13 /** ··· 54 53 #define CXL_HDM_DECODER0_CTRL_LOCK BIT(8) 55 54 #define CXL_HDM_DECODER0_CTRL_COMMIT BIT(9) 56 55 #define CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10) 56 + #define CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11) 57 57 #define CXL_HDM_DECODER0_CTRL_TYPE BIT(12) 58 58 #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24) 59 59 #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28) 60 + #define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i) 61 + #define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i) 60 62 61 63 static inline int cxl_hdm_decoder_count(u32 cap_hdr) 62 64 { 63 65 int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr); 64 66 65 67 return val ? val * 2 : 1; 68 + } 69 + 70 + /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */ 71 + static inline int cxl_to_granularity(u16 ig, unsigned int *val) 72 + { 73 + if (ig > 6) 74 + return -EINVAL; 75 + *val = 256 << ig; 76 + return 0; 77 + } 78 + 79 + /* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */ 80 + static inline int cxl_to_ways(u8 eniw, unsigned int *val) 81 + { 82 + switch (eniw) { 83 + case 0 ... 4: 84 + *val = 1 << eniw; 85 + break; 86 + case 8 ... 10: 87 + *val = 3 << (eniw - 8); 88 + break; 89 + default: 90 + return -EINVAL; 91 + } 92 + 93 + return 0; 94 + } 95 + 96 + static inline int granularity_to_cxl(int g, u16 *ig) 97 + { 98 + if (g > SZ_16K || g < 256 || !is_power_of_2(g)) 99 + return -EINVAL; 100 + *ig = ilog2(g) - 8; 101 + return 0; 102 + } 103 + 104 + static inline int ways_to_cxl(unsigned int ways, u8 *iw) 105 + { 106 + if (ways > 16) 107 + return -EINVAL; 108 + if (is_power_of_2(ways)) { 109 + *iw = ilog2(ways); 110 + return 0; 111 + } 112 + if (ways % 3) 113 + return -EINVAL; 114 + ways /= 3; 115 + if (!is_power_of_2(ways)) 116 + return -EINVAL; 117 + *iw = ilog2(ways) + 8; 118 + return 0; 66 119 } 67 120 68 121 /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ ··· 248 193 */ 249 194 #define CXL_DECODER_MAX_INTERLEAVE 16 250 195 196 + #define CXL_DECODER_MIN_GRANULARITY 256 197 + 251 198 /** 252 - * struct cxl_decoder - CXL address range decode configuration 199 + * struct cxl_decoder - Common CXL HDM Decoder Attributes 253 200 * @dev: this decoder's device 254 201 * @id: kernel device name id 255 - * @platform_res: address space resources considered by root decoder 256 - * @decoder_range: address space resources considered by midlevel decoder 202 + * @hpa_range: Host physical address range mapped by this decoder 257 203 * @interleave_ways: number of cxl_dports in this decode 258 204 * @interleave_granularity: data stride per dport 259 205 * @target_type: accelerator vs expander (type2 vs type3) selector 206 + * @region: currently assigned region for this decoder 260 207 * @flags: memory type capabilities and locking 261 - * @target_lock: coordinate coherent reads of the target list 262 - * @nr_targets: number of elements in @target 263 - * @target: active ordered target list in current decoder configuration 264 - */ 208 + * @commit: device/decoder-type specific callback to commit settings to hw 209 + * @reset: device/decoder-type specific callback to reset hw settings 210 + */ 265 211 struct cxl_decoder { 266 212 struct device dev; 267 213 int id; 268 - union { 269 - struct resource platform_res; 270 - struct range decoder_range; 271 - }; 214 + struct range hpa_range; 272 215 int interleave_ways; 273 216 int interleave_granularity; 274 217 enum cxl_decoder_type target_type; 218 + struct cxl_region *region; 275 219 unsigned long flags; 220 + int (*commit)(struct cxl_decoder *cxld); 221 + int (*reset)(struct cxl_decoder *cxld); 222 + }; 223 + 224 + /* 225 + * CXL_DECODER_DEAD prevents endpoints from being reattached to regions 226 + * while cxld_unregister() is running 227 + */ 228 + enum cxl_decoder_mode { 229 + CXL_DECODER_NONE, 230 + CXL_DECODER_RAM, 231 + CXL_DECODER_PMEM, 232 + CXL_DECODER_MIXED, 233 + CXL_DECODER_DEAD, 234 + }; 235 + 236 + /** 237 + * struct cxl_endpoint_decoder - Endpoint / SPA to DPA decoder 238 + * @cxld: base cxl_decoder_object 239 + * @dpa_res: actively claimed DPA span of this decoder 240 + * @skip: offset into @dpa_res where @cxld.hpa_range maps 241 + * @mode: which memory type / access-mode-partition this decoder targets 242 + * @pos: interleave position in @cxld.region 243 + */ 244 + struct cxl_endpoint_decoder { 245 + struct cxl_decoder cxld; 246 + struct resource *dpa_res; 247 + resource_size_t skip; 248 + enum cxl_decoder_mode mode; 249 + int pos; 250 + }; 251 + 252 + /** 253 + * struct cxl_switch_decoder - Switch specific CXL HDM Decoder 254 + * @cxld: base cxl_decoder object 255 + * @target_lock: coordinate coherent reads of the target list 256 + * @nr_targets: number of elements in @target 257 + * @target: active ordered target list in current decoder configuration 258 + * 259 + * The 'switch' decoder type represents the decoder instances of cxl_port's that 260 + * route from the root of a CXL memory decode topology to the endpoints. They 261 + * come in two flavors, root-level decoders, statically defined by platform 262 + * firmware, and mid-level decoders, where interleave-granularity, 263 + * interleave-width, and the target list are mutable. 264 + */ 265 + struct cxl_switch_decoder { 266 + struct cxl_decoder cxld; 276 267 seqlock_t target_lock; 277 268 int nr_targets; 278 269 struct cxl_dport *target[]; 279 270 }; 280 271 272 + 273 + /** 274 + * struct cxl_root_decoder - Static platform CXL address decoder 275 + * @res: host / parent resource for region allocations 276 + * @region_id: region id for next region provisioning event 277 + * @calc_hb: which host bridge covers the n'th position by granularity 278 + * @cxlsd: base cxl switch decoder 279 + */ 280 + struct cxl_root_decoder { 281 + struct resource *res; 282 + atomic_t region_id; 283 + struct cxl_dport *(*calc_hb)(struct cxl_root_decoder *cxlrd, int pos); 284 + struct cxl_switch_decoder cxlsd; 285 + }; 286 + 287 + /* 288 + * enum cxl_config_state - State machine for region configuration 289 + * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely 290 + * @CXL_CONFIG_INTERLEAVE_ACTIVE: region size has been set, no more 291 + * changes to interleave_ways or interleave_granularity 292 + * @CXL_CONFIG_ACTIVE: All targets have been added the region is now 293 + * active 294 + * @CXL_CONFIG_RESET_PENDING: see commit_store() 295 + * @CXL_CONFIG_COMMIT: Soft-config has been committed to hardware 296 + */ 297 + enum cxl_config_state { 298 + CXL_CONFIG_IDLE, 299 + CXL_CONFIG_INTERLEAVE_ACTIVE, 300 + CXL_CONFIG_ACTIVE, 301 + CXL_CONFIG_RESET_PENDING, 302 + CXL_CONFIG_COMMIT, 303 + }; 304 + 305 + /** 306 + * struct cxl_region_params - region settings 307 + * @state: allow the driver to lockdown further parameter changes 308 + * @uuid: unique id for persistent regions 309 + * @interleave_ways: number of endpoints in the region 310 + * @interleave_granularity: capacity each endpoint contributes to a stripe 311 + * @res: allocated iomem capacity for this region 312 + * @targets: active ordered targets in current decoder configuration 313 + * @nr_targets: number of targets 314 + * 315 + * State transitions are protected by the cxl_region_rwsem 316 + */ 317 + struct cxl_region_params { 318 + enum cxl_config_state state; 319 + uuid_t uuid; 320 + int interleave_ways; 321 + int interleave_granularity; 322 + struct resource *res; 323 + struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE]; 324 + int nr_targets; 325 + }; 326 + 327 + /** 328 + * struct cxl_region - CXL region 329 + * @dev: This region's device 330 + * @id: This region's id. Id is globally unique across all regions 331 + * @mode: Endpoint decoder allocation / access mode 332 + * @type: Endpoint decoder target type 333 + * @params: active + config params for the region 334 + */ 335 + struct cxl_region { 336 + struct device dev; 337 + int id; 338 + enum cxl_decoder_mode mode; 339 + enum cxl_decoder_type type; 340 + struct cxl_region_params params; 341 + }; 281 342 282 343 /** 283 344 * enum cxl_nvdimm_brige_state - state machine for managing bus rescans ··· 422 251 struct cxl_nvdimm { 423 252 struct device dev; 424 253 struct cxl_memdev *cxlmd; 425 - struct nvdimm *nvdimm; 254 + struct cxl_nvdimm_bridge *bridge; 255 + struct cxl_pmem_region *region; 256 + }; 257 + 258 + struct cxl_pmem_region_mapping { 259 + struct cxl_memdev *cxlmd; 260 + struct cxl_nvdimm *cxl_nvd; 261 + u64 start; 262 + u64 size; 263 + int position; 264 + }; 265 + 266 + struct cxl_pmem_region { 267 + struct device dev; 268 + struct cxl_region *cxlr; 269 + struct nd_region *nd_region; 270 + struct cxl_nvdimm_bridge *bridge; 271 + struct range hpa_range; 272 + int nr_mappings; 273 + struct cxl_pmem_region_mapping mapping[]; 426 274 }; 427 275 428 276 /** ··· 450 260 * decode hierarchy. 451 261 * @dev: this port's device 452 262 * @uport: PCI or platform device implementing the upstream port capability 263 + * @host_bridge: Shortcut to the platform attach point for this port 453 264 * @id: id for port device-name 454 265 * @dports: cxl_dport instances referenced by decoders 455 266 * @endpoints: cxl_ep instances, endpoints that are a descendant of this port 267 + * @regions: cxl_region_ref instances, regions mapped by this port 268 + * @parent_dport: dport that points to this port in the parent 456 269 * @decoder_ida: allocator for decoder ids 270 + * @hdm_end: track last allocated HDM decoder instance for allocation ordering 271 + * @commit_end: cursor to track highest committed decoder for commit ordering 457 272 * @component_reg_phys: component register capability base address (optional) 458 273 * @dead: last ep has been removed, force port re-creation 459 274 * @depth: How deep this port is relative to the root. depth 0 is the root. 275 + * @cdat: Cached CDAT data 276 + * @cdat_available: Should a CDAT attribute be available in sysfs 460 277 */ 461 278 struct cxl_port { 462 279 struct device dev; 463 280 struct device *uport; 281 + struct device *host_bridge; 464 282 int id; 465 - struct list_head dports; 466 - struct list_head endpoints; 283 + struct xarray dports; 284 + struct xarray endpoints; 285 + struct xarray regions; 286 + struct cxl_dport *parent_dport; 467 287 struct ida decoder_ida; 288 + int hdm_end; 289 + int commit_end; 468 290 resource_size_t component_reg_phys; 469 291 bool dead; 470 292 unsigned int depth; 293 + struct cxl_cdat { 294 + void *table; 295 + size_t length; 296 + } cdat; 297 + bool cdat_available; 471 298 }; 299 + 300 + static inline struct cxl_dport * 301 + cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev) 302 + { 303 + return xa_load(&port->dports, (unsigned long)dport_dev); 304 + } 472 305 473 306 /** 474 307 * struct cxl_dport - CXL downstream port ··· 499 286 * @port_id: unique hardware identifier for dport in decoder target list 500 287 * @component_reg_phys: downstream port component registers 501 288 * @port: reference to cxl_port that contains this downstream port 502 - * @list: node for a cxl_port's list of cxl_dport instances 503 289 */ 504 290 struct cxl_dport { 505 291 struct device *dport; 506 292 int port_id; 507 293 resource_size_t component_reg_phys; 508 294 struct cxl_port *port; 509 - struct list_head list; 510 295 }; 511 296 512 297 /** 513 298 * struct cxl_ep - track an endpoint's interest in a port 514 299 * @ep: device that hosts a generic CXL endpoint (expander or accelerator) 515 - * @list: node on port->endpoints list 300 + * @dport: which dport routes to this endpoint on @port 301 + * @next: cxl switch port across the link attached to @dport NULL if 302 + * attached to an endpoint 516 303 */ 517 304 struct cxl_ep { 518 305 struct device *ep; 519 - struct list_head list; 306 + struct cxl_dport *dport; 307 + struct cxl_port *next; 308 + }; 309 + 310 + /** 311 + * struct cxl_region_ref - track a region's interest in a port 312 + * @port: point in topology to install this reference 313 + * @decoder: decoder assigned for @region in @port 314 + * @region: region for this reference 315 + * @endpoints: cxl_ep references for region members beneath @port 316 + * @nr_targets_set: track how many targets have been programmed during setup 317 + * @nr_eps: number of endpoints beneath @port 318 + * @nr_targets: number of distinct targets needed to reach @nr_eps 319 + */ 320 + struct cxl_region_ref { 321 + struct cxl_port *port; 322 + struct cxl_decoder *decoder; 323 + struct cxl_region *region; 324 + struct xarray endpoints; 325 + int nr_targets_set; 326 + int nr_eps; 327 + int nr_targets; 520 328 }; 521 329 522 330 /* ··· 559 325 struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port); 560 326 struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, 561 327 resource_size_t component_reg_phys, 562 - struct cxl_port *parent_port); 328 + struct cxl_dport *parent_dport); 329 + int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd, 330 + struct cxl_dport *parent_dport); 563 331 struct cxl_port *find_cxl_root(struct device *dev); 564 332 int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); 565 333 int cxl_bus_rescan(void); 566 - struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd); 334 + struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, 335 + struct cxl_dport **dport); 567 336 bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd); 568 337 569 338 struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port, 570 339 struct device *dport, int port_id, 571 340 resource_size_t component_reg_phys); 572 - struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port, 573 - const struct device *dev); 574 341 575 342 struct cxl_decoder *to_cxl_decoder(struct device *dev); 343 + struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev); 344 + struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev); 576 345 bool is_root_decoder(struct device *dev); 577 346 bool is_endpoint_decoder(struct device *dev); 578 - bool is_cxl_decoder(struct device *dev); 579 - struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 580 - unsigned int nr_targets); 581 - struct cxl_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 582 - unsigned int nr_targets); 347 + struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, 348 + unsigned int nr_targets); 349 + struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, 350 + unsigned int nr_targets); 583 351 int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); 584 - struct cxl_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port); 352 + struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port); 585 353 int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map); 586 354 int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); 587 355 int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); ··· 592 356 struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port); 593 357 int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm); 594 358 int devm_cxl_add_passthrough_decoder(struct cxl_port *port); 359 + 360 + bool is_cxl_region(struct device *dev); 595 361 596 362 extern struct bus_type cxl_bus_type; 597 363 ··· 623 385 #define CXL_DEVICE_PORT 3 624 386 #define CXL_DEVICE_ROOT 4 625 387 #define CXL_DEVICE_MEMORY_EXPANDER 5 388 + #define CXL_DEVICE_REGION 6 389 + #define CXL_DEVICE_PMEM_REGION 7 626 390 627 391 #define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*") 628 392 #define CXL_MODALIAS_FMT "cxl:t%d" ··· 636 396 bool is_cxl_nvdimm(struct device *dev); 637 397 bool is_cxl_nvdimm_bridge(struct device *dev); 638 398 int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); 639 - struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd); 399 + struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct device *dev); 400 + 401 + #ifdef CONFIG_CXL_REGION 402 + bool is_cxl_pmem_region(struct device *dev); 403 + struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev); 404 + #else 405 + static inline bool is_cxl_pmem_region(struct device *dev) 406 + { 407 + return false; 408 + } 409 + static inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev) 410 + { 411 + return NULL; 412 + } 413 + #endif 640 414 641 415 /* 642 416 * Unit test builds overrides this to __weak, find the 'strong' version
+38 -4
drivers/cxl/cxlmem.h
··· 50 50 return container_of(dev, struct cxl_memdev, dev); 51 51 } 52 52 53 + static inline struct cxl_port *cxled_to_port(struct cxl_endpoint_decoder *cxled) 54 + { 55 + return to_cxl_port(cxled->cxld.dev.parent); 56 + } 57 + 58 + static inline struct cxl_port *cxlrd_to_port(struct cxl_root_decoder *cxlrd) 59 + { 60 + return to_cxl_port(cxlrd->cxlsd.cxld.dev.parent); 61 + } 62 + 63 + static inline struct cxl_memdev * 64 + cxled_to_memdev(struct cxl_endpoint_decoder *cxled) 65 + { 66 + struct cxl_port *port = to_cxl_port(cxled->cxld.dev.parent); 67 + 68 + return to_cxl_memdev(port->uport); 69 + } 70 + 53 71 bool is_cxl_memdev(struct device *dev); 54 72 static inline bool is_cxl_endpoint(struct cxl_port *port) 55 73 { ··· 196 178 * @firmware_version: Firmware version for the memory device. 197 179 * @enabled_cmds: Hardware commands found enabled in CEL. 198 180 * @exclusive_cmds: Commands that are kernel-internal only 199 - * @pmem_range: Active Persistent memory capacity configuration 200 - * @ram_range: Active Volatile memory capacity configuration 181 + * @dpa_res: Overall DPA resource tree for the device 182 + * @pmem_res: Active Persistent memory capacity configuration 183 + * @ram_res: Active Volatile memory capacity configuration 201 184 * @total_bytes: sum of all possible capacities 202 185 * @volatile_only_bytes: hard volatile capacity 203 186 * @persistent_only_bytes: hard persistent capacity ··· 210 191 * @component_reg_phys: register base of component registers 211 192 * @info: Cached DVSEC information about the device. 212 193 * @serial: PCIe Device Serial Number 194 + * @doe_mbs: PCI DOE mailbox array 213 195 * @mbox_send: @dev specific transport for transmitting mailbox commands 214 196 * 215 197 * See section 8.2.9.5.2 Capacity Configuration and Label Storage for ··· 229 209 DECLARE_BITMAP(enabled_cmds, CXL_MEM_COMMAND_ID_MAX); 230 210 DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); 231 211 232 - struct range pmem_range; 233 - struct range ram_range; 212 + struct resource dpa_res; 213 + struct resource pmem_res; 214 + struct resource ram_res; 234 215 u64 total_bytes; 235 216 u64 volatile_only_bytes; 236 217 u64 persistent_only_bytes; ··· 244 223 245 224 resource_size_t component_reg_phys; 246 225 u64 serial; 226 + 227 + struct xarray doe_mbs; 247 228 248 229 int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd); 249 230 }; ··· 322 299 u8 qos_telemetry_caps; 323 300 } __packed; 324 301 302 + struct cxl_mbox_get_partition_info { 303 + __le64 active_volatile_cap; 304 + __le64 active_persistent_cap; 305 + __le64 next_volatile_cap; 306 + __le64 next_persistent_cap; 307 + } __packed; 308 + 325 309 struct cxl_mbox_get_lsa { 326 310 __le32 offset; 327 311 __le32 length; ··· 400 370 unsigned int interleave_mask; 401 371 struct cxl_port *port; 402 372 }; 373 + 374 + struct seq_file; 375 + struct dentry *cxl_debugfs_create_dir(const char *dir); 376 + void cxl_dpa_debug(struct seq_file *file, struct cxl_dev_state *cxlds); 403 377 #endif /* __CXL_MEM_H__ */
+1
drivers/cxl/cxlpci.h
··· 74 74 int devm_cxl_port_enumerate_dports(struct cxl_port *port); 75 75 struct cxl_dev_state; 76 76 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm); 77 + void read_cdat_data(struct cxl_port *port); 77 78 #endif /* __CXL_PCI_H__ */
+26 -29
drivers/cxl/mem.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 + #include <linux/debugfs.h> 3 4 #include <linux/device.h> 4 5 #include <linux/module.h> 5 6 #include <linux/pci.h> ··· 25 24 * in higher level operations. 26 25 */ 27 26 28 - static int create_endpoint(struct cxl_memdev *cxlmd, 29 - struct cxl_port *parent_port) 30 - { 31 - struct cxl_dev_state *cxlds = cxlmd->cxlds; 32 - struct cxl_port *endpoint; 33 - int rc; 34 - 35 - endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev, 36 - cxlds->component_reg_phys, parent_port); 37 - if (IS_ERR(endpoint)) 38 - return PTR_ERR(endpoint); 39 - 40 - dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev)); 41 - 42 - rc = cxl_endpoint_autoremove(cxlmd, endpoint); 43 - if (rc) 44 - return rc; 45 - 46 - if (!endpoint->dev.driver) { 47 - dev_err(&cxlmd->dev, "%s failed probe\n", 48 - dev_name(&endpoint->dev)); 49 - return -ENXIO; 50 - } 51 - 52 - return 0; 53 - } 54 - 55 27 static void enable_suspend(void *data) 56 28 { 57 29 cxl_mem_active_dec(); 30 + } 31 + 32 + static void remove_debugfs(void *dentry) 33 + { 34 + debugfs_remove_recursive(dentry); 35 + } 36 + 37 + static int cxl_mem_dpa_show(struct seq_file *file, void *data) 38 + { 39 + struct device *dev = file->private; 40 + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 41 + 42 + cxl_dpa_debug(file, cxlmd->cxlds); 43 + 44 + return 0; 58 45 } 59 46 60 47 static int cxl_mem_probe(struct device *dev) 61 48 { 62 49 struct cxl_memdev *cxlmd = to_cxl_memdev(dev); 63 50 struct cxl_port *parent_port; 51 + struct cxl_dport *dport; 52 + struct dentry *dentry; 64 53 int rc; 65 54 66 55 /* ··· 64 73 if (work_pending(&cxlmd->detach_work)) 65 74 return -EBUSY; 66 75 76 + dentry = cxl_debugfs_create_dir(dev_name(dev)); 77 + debugfs_create_devm_seqfile(dev, "dpamem", dentry, cxl_mem_dpa_show); 78 + rc = devm_add_action_or_reset(dev, remove_debugfs, dentry); 79 + if (rc) 80 + return rc; 81 + 67 82 rc = devm_cxl_enumerate_ports(cxlmd); 68 83 if (rc) 69 84 return rc; 70 85 71 - parent_port = cxl_mem_find_port(cxlmd); 86 + parent_port = cxl_mem_find_port(cxlmd, &dport); 72 87 if (!parent_port) { 73 88 dev_err(dev, "CXL port topology not found\n"); 74 89 return -ENXIO; ··· 88 91 goto unlock; 89 92 } 90 93 91 - rc = create_endpoint(cxlmd, parent_port); 94 + rc = devm_cxl_add_endpoint(cxlmd, dport); 92 95 unlock: 93 96 device_unlock(&parent_port->dev); 94 97 put_device(&parent_port->dev);
+45 -1
drivers/cxl/pci.c
··· 8 8 #include <linux/mutex.h> 9 9 #include <linux/list.h> 10 10 #include <linux/pci.h> 11 + #include <linux/pci-doe.h> 11 12 #include <linux/io.h> 12 13 #include "cxlmem.h" 13 14 #include "cxlpci.h" ··· 387 386 return rc; 388 387 } 389 388 389 + static void cxl_pci_destroy_doe(void *mbs) 390 + { 391 + xa_destroy(mbs); 392 + } 393 + 394 + static void devm_cxl_pci_create_doe(struct cxl_dev_state *cxlds) 395 + { 396 + struct device *dev = cxlds->dev; 397 + struct pci_dev *pdev = to_pci_dev(dev); 398 + u16 off = 0; 399 + 400 + xa_init(&cxlds->doe_mbs); 401 + if (devm_add_action(&pdev->dev, cxl_pci_destroy_doe, &cxlds->doe_mbs)) { 402 + dev_err(dev, "Failed to create XArray for DOE's\n"); 403 + return; 404 + } 405 + 406 + /* 407 + * Mailbox creation is best effort. Higher layers must determine if 408 + * the lack of a mailbox for their protocol is a device failure or not. 409 + */ 410 + pci_doe_for_each_off(pdev, off) { 411 + struct pci_doe_mb *doe_mb; 412 + 413 + doe_mb = pcim_doe_create_mb(pdev, off); 414 + if (IS_ERR(doe_mb)) { 415 + dev_err(dev, "Failed to create MB object for MB @ %x\n", 416 + off); 417 + continue; 418 + } 419 + 420 + if (xa_insert(&cxlds->doe_mbs, off, doe_mb, GFP_KERNEL)) { 421 + dev_err(dev, "xa_insert failed to insert MB @ %x\n", 422 + off); 423 + continue; 424 + } 425 + 426 + dev_dbg(dev, "Created DOE mailbox @%x\n", off); 427 + } 428 + } 429 + 390 430 static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 391 431 { 392 432 struct cxl_register_map map; ··· 476 434 477 435 cxlds->component_reg_phys = cxl_regmap_to_base(pdev, &map); 478 436 437 + devm_cxl_pci_create_doe(cxlds); 438 + 479 439 rc = cxl_pci_setup_mailbox(cxlds); 480 440 if (rc) 481 441 return rc; ··· 498 454 if (IS_ERR(cxlmd)) 499 455 return PTR_ERR(cxlmd); 500 456 501 - if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 457 + if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) 502 458 rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd); 503 459 504 460 return rc;
+254 -5
drivers/cxl/pmem.c
··· 7 7 #include <linux/ndctl.h> 8 8 #include <linux/async.h> 9 9 #include <linux/slab.h> 10 + #include <linux/nd.h> 10 11 #include "cxlmem.h" 11 12 #include "cxl.h" 12 13 ··· 27 26 28 27 static void unregister_nvdimm(void *nvdimm) 29 28 { 29 + struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); 30 + struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge; 31 + struct cxl_pmem_region *cxlr_pmem; 32 + 33 + device_lock(&cxl_nvb->dev); 34 + cxlr_pmem = cxl_nvd->region; 35 + dev_set_drvdata(&cxl_nvd->dev, NULL); 36 + cxl_nvd->region = NULL; 37 + device_unlock(&cxl_nvb->dev); 38 + 39 + if (cxlr_pmem) { 40 + device_release_driver(&cxlr_pmem->dev); 41 + put_device(&cxlr_pmem->dev); 42 + } 43 + 30 44 nvdimm_delete(nvdimm); 45 + cxl_nvd->bridge = NULL; 31 46 } 32 47 33 48 static int cxl_nvdimm_probe(struct device *dev) ··· 56 39 struct nvdimm *nvdimm; 57 40 int rc; 58 41 59 - cxl_nvb = cxl_find_nvdimm_bridge(cxl_nvd); 42 + cxl_nvb = cxl_find_nvdimm_bridge(dev); 60 43 if (!cxl_nvb) 61 44 return -ENXIO; 62 45 ··· 83 66 } 84 67 85 68 dev_set_drvdata(dev, nvdimm); 69 + cxl_nvd->bridge = cxl_nvb; 86 70 rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm); 87 71 out: 88 72 device_unlock(&cxl_nvb->dev); ··· 222 204 return cxl_nvb->nvdimm_bus != NULL; 223 205 } 224 206 225 - static int cxl_nvdimm_release_driver(struct device *dev, void *data) 207 + static int cxl_nvdimm_release_driver(struct device *dev, void *cxl_nvb) 226 208 { 209 + struct cxl_nvdimm *cxl_nvd; 210 + 227 211 if (!is_cxl_nvdimm(dev)) 228 212 return 0; 213 + 214 + cxl_nvd = to_cxl_nvdimm(dev); 215 + if (cxl_nvd->bridge != cxl_nvb) 216 + return 0; 217 + 229 218 device_release_driver(dev); 230 219 return 0; 231 220 } 232 221 233 - static void offline_nvdimm_bus(struct nvdimm_bus *nvdimm_bus) 222 + static int cxl_pmem_region_release_driver(struct device *dev, void *cxl_nvb) 223 + { 224 + struct cxl_pmem_region *cxlr_pmem; 225 + 226 + if (!is_cxl_pmem_region(dev)) 227 + return 0; 228 + 229 + cxlr_pmem = to_cxl_pmem_region(dev); 230 + if (cxlr_pmem->bridge != cxl_nvb) 231 + return 0; 232 + 233 + device_release_driver(dev); 234 + return 0; 235 + } 236 + 237 + static void offline_nvdimm_bus(struct cxl_nvdimm_bridge *cxl_nvb, 238 + struct nvdimm_bus *nvdimm_bus) 234 239 { 235 240 if (!nvdimm_bus) 236 241 return; ··· 263 222 * nvdimm_bus_unregister() rips the nvdimm objects out from 264 223 * underneath them. 265 224 */ 266 - bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_release_driver); 225 + bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb, 226 + cxl_pmem_region_release_driver); 227 + bus_for_each_dev(&cxl_bus_type, NULL, cxl_nvb, 228 + cxl_nvdimm_release_driver); 267 229 nvdimm_bus_unregister(nvdimm_bus); 268 230 } 269 231 ··· 304 260 305 261 dev_dbg(&cxl_nvb->dev, "rescan: %d\n", rc); 306 262 } 307 - offline_nvdimm_bus(victim_bus); 263 + offline_nvdimm_bus(cxl_nvb, victim_bus); 308 264 309 265 put_device(&cxl_nvb->dev); 310 266 } ··· 359 315 .id = CXL_DEVICE_NVDIMM_BRIDGE, 360 316 }; 361 317 318 + static int match_cxl_nvdimm(struct device *dev, void *data) 319 + { 320 + return is_cxl_nvdimm(dev); 321 + } 322 + 323 + static void unregister_nvdimm_region(void *nd_region) 324 + { 325 + struct cxl_nvdimm_bridge *cxl_nvb; 326 + struct cxl_pmem_region *cxlr_pmem; 327 + int i; 328 + 329 + cxlr_pmem = nd_region_provider_data(nd_region); 330 + cxl_nvb = cxlr_pmem->bridge; 331 + device_lock(&cxl_nvb->dev); 332 + for (i = 0; i < cxlr_pmem->nr_mappings; i++) { 333 + struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i]; 334 + struct cxl_nvdimm *cxl_nvd = m->cxl_nvd; 335 + 336 + if (cxl_nvd->region) { 337 + put_device(&cxlr_pmem->dev); 338 + cxl_nvd->region = NULL; 339 + } 340 + } 341 + device_unlock(&cxl_nvb->dev); 342 + 343 + nvdimm_region_delete(nd_region); 344 + } 345 + 346 + static void cxlr_pmem_remove_resource(void *res) 347 + { 348 + remove_resource(res); 349 + } 350 + 351 + struct cxl_pmem_region_info { 352 + u64 offset; 353 + u64 serial; 354 + }; 355 + 356 + static int cxl_pmem_region_probe(struct device *dev) 357 + { 358 + struct nd_mapping_desc mappings[CXL_DECODER_MAX_INTERLEAVE]; 359 + struct cxl_pmem_region *cxlr_pmem = to_cxl_pmem_region(dev); 360 + struct cxl_region *cxlr = cxlr_pmem->cxlr; 361 + struct cxl_pmem_region_info *info = NULL; 362 + struct cxl_nvdimm_bridge *cxl_nvb; 363 + struct nd_interleave_set *nd_set; 364 + struct nd_region_desc ndr_desc; 365 + struct cxl_nvdimm *cxl_nvd; 366 + struct nvdimm *nvdimm; 367 + struct resource *res; 368 + int rc, i = 0; 369 + 370 + cxl_nvb = cxl_find_nvdimm_bridge(&cxlr_pmem->mapping[0].cxlmd->dev); 371 + if (!cxl_nvb) { 372 + dev_dbg(dev, "bridge not found\n"); 373 + return -ENXIO; 374 + } 375 + cxlr_pmem->bridge = cxl_nvb; 376 + 377 + device_lock(&cxl_nvb->dev); 378 + if (!cxl_nvb->nvdimm_bus) { 379 + dev_dbg(dev, "nvdimm bus not found\n"); 380 + rc = -ENXIO; 381 + goto err; 382 + } 383 + 384 + memset(&mappings, 0, sizeof(mappings)); 385 + memset(&ndr_desc, 0, sizeof(ndr_desc)); 386 + 387 + res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); 388 + if (!res) { 389 + rc = -ENOMEM; 390 + goto err; 391 + } 392 + 393 + res->name = "Persistent Memory"; 394 + res->start = cxlr_pmem->hpa_range.start; 395 + res->end = cxlr_pmem->hpa_range.end; 396 + res->flags = IORESOURCE_MEM; 397 + res->desc = IORES_DESC_PERSISTENT_MEMORY; 398 + 399 + rc = insert_resource(&iomem_resource, res); 400 + if (rc) 401 + goto err; 402 + 403 + rc = devm_add_action_or_reset(dev, cxlr_pmem_remove_resource, res); 404 + if (rc) 405 + goto err; 406 + 407 + ndr_desc.res = res; 408 + ndr_desc.provider_data = cxlr_pmem; 409 + 410 + ndr_desc.numa_node = memory_add_physaddr_to_nid(res->start); 411 + ndr_desc.target_node = phys_to_target_node(res->start); 412 + if (ndr_desc.target_node == NUMA_NO_NODE) { 413 + ndr_desc.target_node = ndr_desc.numa_node; 414 + dev_dbg(&cxlr->dev, "changing target node from %d to %d", 415 + NUMA_NO_NODE, ndr_desc.target_node); 416 + } 417 + 418 + nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL); 419 + if (!nd_set) { 420 + rc = -ENOMEM; 421 + goto err; 422 + } 423 + 424 + ndr_desc.memregion = cxlr->id; 425 + set_bit(ND_REGION_CXL, &ndr_desc.flags); 426 + set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc.flags); 427 + 428 + info = kmalloc_array(cxlr_pmem->nr_mappings, sizeof(*info), GFP_KERNEL); 429 + if (!info) { 430 + rc = -ENOMEM; 431 + goto err; 432 + } 433 + 434 + for (i = 0; i < cxlr_pmem->nr_mappings; i++) { 435 + struct cxl_pmem_region_mapping *m = &cxlr_pmem->mapping[i]; 436 + struct cxl_memdev *cxlmd = m->cxlmd; 437 + struct cxl_dev_state *cxlds = cxlmd->cxlds; 438 + struct device *d; 439 + 440 + d = device_find_child(&cxlmd->dev, NULL, match_cxl_nvdimm); 441 + if (!d) { 442 + dev_dbg(dev, "[%d]: %s: no cxl_nvdimm found\n", i, 443 + dev_name(&cxlmd->dev)); 444 + rc = -ENODEV; 445 + goto err; 446 + } 447 + 448 + /* safe to drop ref now with bridge lock held */ 449 + put_device(d); 450 + 451 + cxl_nvd = to_cxl_nvdimm(d); 452 + nvdimm = dev_get_drvdata(&cxl_nvd->dev); 453 + if (!nvdimm) { 454 + dev_dbg(dev, "[%d]: %s: no nvdimm found\n", i, 455 + dev_name(&cxlmd->dev)); 456 + rc = -ENODEV; 457 + goto err; 458 + } 459 + cxl_nvd->region = cxlr_pmem; 460 + get_device(&cxlr_pmem->dev); 461 + m->cxl_nvd = cxl_nvd; 462 + mappings[i] = (struct nd_mapping_desc) { 463 + .nvdimm = nvdimm, 464 + .start = m->start, 465 + .size = m->size, 466 + .position = i, 467 + }; 468 + info[i].offset = m->start; 469 + info[i].serial = cxlds->serial; 470 + } 471 + ndr_desc.num_mappings = cxlr_pmem->nr_mappings; 472 + ndr_desc.mapping = mappings; 473 + 474 + /* 475 + * TODO enable CXL labels which skip the need for 'interleave-set cookie' 476 + */ 477 + nd_set->cookie1 = 478 + nd_fletcher64(info, sizeof(*info) * cxlr_pmem->nr_mappings, 0); 479 + nd_set->cookie2 = nd_set->cookie1; 480 + ndr_desc.nd_set = nd_set; 481 + 482 + cxlr_pmem->nd_region = 483 + nvdimm_pmem_region_create(cxl_nvb->nvdimm_bus, &ndr_desc); 484 + if (!cxlr_pmem->nd_region) { 485 + rc = -ENOMEM; 486 + goto err; 487 + } 488 + 489 + rc = devm_add_action_or_reset(dev, unregister_nvdimm_region, 490 + cxlr_pmem->nd_region); 491 + out: 492 + kfree(info); 493 + device_unlock(&cxl_nvb->dev); 494 + put_device(&cxl_nvb->dev); 495 + 496 + return rc; 497 + 498 + err: 499 + dev_dbg(dev, "failed to create nvdimm region\n"); 500 + for (i--; i >= 0; i--) { 501 + nvdimm = mappings[i].nvdimm; 502 + cxl_nvd = nvdimm_provider_data(nvdimm); 503 + put_device(&cxl_nvd->region->dev); 504 + cxl_nvd->region = NULL; 505 + } 506 + goto out; 507 + } 508 + 509 + static struct cxl_driver cxl_pmem_region_driver = { 510 + .name = "cxl_pmem_region", 511 + .probe = cxl_pmem_region_probe, 512 + .id = CXL_DEVICE_PMEM_REGION, 513 + }; 514 + 362 515 /* 363 516 * Return all bridges to the CXL_NVB_NEW state to invalidate any 364 517 * ->state_work referring to the now destroyed cxl_pmem_wq. ··· 600 359 if (rc) 601 360 goto err_nvdimm; 602 361 362 + rc = cxl_driver_register(&cxl_pmem_region_driver); 363 + if (rc) 364 + goto err_region; 365 + 603 366 return 0; 604 367 368 + err_region: 369 + cxl_driver_unregister(&cxl_nvdimm_driver); 605 370 err_nvdimm: 606 371 cxl_driver_unregister(&cxl_nvdimm_bridge_driver); 607 372 err_bridge: ··· 617 370 618 371 static __exit void cxl_pmem_exit(void) 619 372 { 373 + cxl_driver_unregister(&cxl_pmem_region_driver); 620 374 cxl_driver_unregister(&cxl_nvdimm_driver); 621 375 cxl_driver_unregister(&cxl_nvdimm_bridge_driver); 622 376 destroy_cxl_pmem_wq(); ··· 629 381 MODULE_IMPORT_NS(CXL); 630 382 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE); 631 383 MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM); 384 + MODULE_ALIAS_CXL(CXL_DEVICE_PMEM_REGION);
+53
drivers/cxl/port.c
··· 53 53 struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); 54 54 struct cxl_dev_state *cxlds = cxlmd->cxlds; 55 55 56 + /* Cache the data early to ensure is_visible() works */ 57 + read_cdat_data(port); 58 + 56 59 get_device(&cxlmd->dev); 57 60 rc = devm_add_action_or_reset(dev, schedule_detach, cxlmd); 58 61 if (rc) ··· 81 78 return 0; 82 79 } 83 80 81 + static ssize_t CDAT_read(struct file *filp, struct kobject *kobj, 82 + struct bin_attribute *bin_attr, char *buf, 83 + loff_t offset, size_t count) 84 + { 85 + struct device *dev = kobj_to_dev(kobj); 86 + struct cxl_port *port = to_cxl_port(dev); 87 + 88 + if (!port->cdat_available) 89 + return -ENXIO; 90 + 91 + if (!port->cdat.table) 92 + return 0; 93 + 94 + return memory_read_from_buffer(buf, count, &offset, 95 + port->cdat.table, 96 + port->cdat.length); 97 + } 98 + 99 + static BIN_ATTR_ADMIN_RO(CDAT, 0); 100 + 101 + static umode_t cxl_port_bin_attr_is_visible(struct kobject *kobj, 102 + struct bin_attribute *attr, int i) 103 + { 104 + struct device *dev = kobj_to_dev(kobj); 105 + struct cxl_port *port = to_cxl_port(dev); 106 + 107 + if ((attr == &bin_attr_CDAT) && port->cdat_available) 108 + return attr->attr.mode; 109 + 110 + return 0; 111 + } 112 + 113 + static struct bin_attribute *cxl_cdat_bin_attributes[] = { 114 + &bin_attr_CDAT, 115 + NULL, 116 + }; 117 + 118 + static struct attribute_group cxl_cdat_attribute_group = { 119 + .bin_attrs = cxl_cdat_bin_attributes, 120 + .is_bin_visible = cxl_port_bin_attr_is_visible, 121 + }; 122 + 123 + static const struct attribute_group *cxl_port_attribute_groups[] = { 124 + &cxl_cdat_attribute_group, 125 + NULL, 126 + }; 127 + 84 128 static struct cxl_driver cxl_port_driver = { 85 129 .name = "cxl_port", 86 130 .probe = cxl_port_probe, 87 131 .id = CXL_DEVICE_PORT, 132 + .drv = { 133 + .dev_groups = cxl_port_attribute_groups, 134 + }, 88 135 }; 89 136 90 137 module_cxl_driver(cxl_port_driver);
+21 -7
drivers/nvdimm/region_devs.c
··· 133 133 put_device(&nvdimm->dev); 134 134 } 135 135 free_percpu(nd_region->lane); 136 - memregion_free(nd_region->id); 136 + if (!test_bit(ND_REGION_CXL, &nd_region->flags)) 137 + memregion_free(nd_region->id); 137 138 kfree(nd_region); 138 139 } 139 140 ··· 983 982 984 983 if (!nd_region) 985 984 return NULL; 986 - nd_region->id = memregion_alloc(GFP_KERNEL); 987 - if (nd_region->id < 0) 988 - goto err_id; 985 + /* CXL pre-assigns memregion ids before creating nvdimm regions */ 986 + if (test_bit(ND_REGION_CXL, &ndr_desc->flags)) { 987 + nd_region->id = ndr_desc->memregion; 988 + } else { 989 + nd_region->id = memregion_alloc(GFP_KERNEL); 990 + if (nd_region->id < 0) 991 + goto err_id; 992 + } 989 993 990 994 nd_region->lane = alloc_percpu(struct nd_percpu_lane); 991 995 if (!nd_region->lane) ··· 1049 1043 1050 1044 return nd_region; 1051 1045 1052 - err_percpu: 1053 - memregion_free(nd_region->id); 1054 - err_id: 1046 + err_percpu: 1047 + if (!test_bit(ND_REGION_CXL, &ndr_desc->flags)) 1048 + memregion_free(nd_region->id); 1049 + err_id: 1055 1050 kfree(nd_region); 1056 1051 return NULL; 1057 1052 } ··· 1074 1067 __func__); 1075 1068 } 1076 1069 EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); 1070 + 1071 + void nvdimm_region_delete(struct nd_region *nd_region) 1072 + { 1073 + if (nd_region) 1074 + nd_device_unregister(&nd_region->dev, ND_SYNC); 1075 + } 1076 + EXPORT_SYMBOL_GPL(nvdimm_region_delete); 1077 1077 1078 1078 int nvdimm_flush(struct nd_region *nd_region, struct bio *bio) 1079 1079 {
+3
drivers/pci/Kconfig
··· 121 121 config PCI_ATS 122 122 bool 123 123 124 + config PCI_DOE 125 + bool 126 + 124 127 config PCI_ECAM 125 128 bool 126 129
+1
drivers/pci/Makefile
··· 31 31 obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o 32 32 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o 33 33 obj-$(CONFIG_VGA_ARB) += vgaarb.o 34 + obj-$(CONFIG_PCI_DOE) += doe.o 34 35 35 36 # Endpoint library must be initialized before its users 36 37 obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
+536
drivers/pci/doe.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Data Object Exchange 4 + * PCIe r6.0, sec 6.30 DOE 5 + * 6 + * Copyright (C) 2021 Huawei 7 + * Jonathan Cameron <Jonathan.Cameron@huawei.com> 8 + * 9 + * Copyright (C) 2022 Intel Corporation 10 + * Ira Weiny <ira.weiny@intel.com> 11 + */ 12 + 13 + #define dev_fmt(fmt) "DOE: " fmt 14 + 15 + #include <linux/bitfield.h> 16 + #include <linux/delay.h> 17 + #include <linux/jiffies.h> 18 + #include <linux/mutex.h> 19 + #include <linux/pci.h> 20 + #include <linux/pci-doe.h> 21 + #include <linux/workqueue.h> 22 + 23 + #define PCI_DOE_PROTOCOL_DISCOVERY 0 24 + 25 + /* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */ 26 + #define PCI_DOE_TIMEOUT HZ 27 + #define PCI_DOE_POLL_INTERVAL (PCI_DOE_TIMEOUT / 128) 28 + 29 + #define PCI_DOE_FLAG_CANCEL 0 30 + #define PCI_DOE_FLAG_DEAD 1 31 + 32 + /** 33 + * struct pci_doe_mb - State for a single DOE mailbox 34 + * 35 + * This state is used to manage a single DOE mailbox capability. All fields 36 + * should be considered opaque to the consumers and the structure passed into 37 + * the helpers below after being created by devm_pci_doe_create() 38 + * 39 + * @pdev: PCI device this mailbox belongs to 40 + * @cap_offset: Capability offset 41 + * @prots: Array of protocols supported (encoded as long values) 42 + * @wq: Wait queue for work item 43 + * @work_queue: Queue of pci_doe_work items 44 + * @flags: Bit array of PCI_DOE_FLAG_* flags 45 + */ 46 + struct pci_doe_mb { 47 + struct pci_dev *pdev; 48 + u16 cap_offset; 49 + struct xarray prots; 50 + 51 + wait_queue_head_t wq; 52 + struct workqueue_struct *work_queue; 53 + unsigned long flags; 54 + }; 55 + 56 + static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout) 57 + { 58 + if (wait_event_timeout(doe_mb->wq, 59 + test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags), 60 + timeout)) 61 + return -EIO; 62 + return 0; 63 + } 64 + 65 + static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val) 66 + { 67 + struct pci_dev *pdev = doe_mb->pdev; 68 + int offset = doe_mb->cap_offset; 69 + 70 + pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val); 71 + } 72 + 73 + static int pci_doe_abort(struct pci_doe_mb *doe_mb) 74 + { 75 + struct pci_dev *pdev = doe_mb->pdev; 76 + int offset = doe_mb->cap_offset; 77 + unsigned long timeout_jiffies; 78 + 79 + pci_dbg(pdev, "[%x] Issuing Abort\n", offset); 80 + 81 + timeout_jiffies = jiffies + PCI_DOE_TIMEOUT; 82 + pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT); 83 + 84 + do { 85 + int rc; 86 + u32 val; 87 + 88 + rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL); 89 + if (rc) 90 + return rc; 91 + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); 92 + 93 + /* Abort success! */ 94 + if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) && 95 + !FIELD_GET(PCI_DOE_STATUS_BUSY, val)) 96 + return 0; 97 + 98 + } while (!time_after(jiffies, timeout_jiffies)); 99 + 100 + /* Abort has timed out and the MB is dead */ 101 + pci_err(pdev, "[%x] ABORT timed out\n", offset); 102 + return -EIO; 103 + } 104 + 105 + static int pci_doe_send_req(struct pci_doe_mb *doe_mb, 106 + struct pci_doe_task *task) 107 + { 108 + struct pci_dev *pdev = doe_mb->pdev; 109 + int offset = doe_mb->cap_offset; 110 + u32 val; 111 + int i; 112 + 113 + /* 114 + * Check the DOE busy bit is not set. If it is set, this could indicate 115 + * someone other than Linux (e.g. firmware) is using the mailbox. Note 116 + * it is expected that firmware and OS will negotiate access rights via 117 + * an, as yet to be defined, method. 118 + */ 119 + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); 120 + if (FIELD_GET(PCI_DOE_STATUS_BUSY, val)) 121 + return -EBUSY; 122 + 123 + if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) 124 + return -EIO; 125 + 126 + /* Write DOE Header */ 127 + val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) | 128 + FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type); 129 + pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val); 130 + /* Length is 2 DW of header + length of payload in DW */ 131 + pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, 132 + FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, 133 + 2 + task->request_pl_sz / 134 + sizeof(u32))); 135 + for (i = 0; i < task->request_pl_sz / sizeof(u32); i++) 136 + pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, 137 + task->request_pl[i]); 138 + 139 + pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO); 140 + 141 + return 0; 142 + } 143 + 144 + static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb) 145 + { 146 + struct pci_dev *pdev = doe_mb->pdev; 147 + int offset = doe_mb->cap_offset; 148 + u32 val; 149 + 150 + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); 151 + if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) 152 + return true; 153 + return false; 154 + } 155 + 156 + static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) 157 + { 158 + struct pci_dev *pdev = doe_mb->pdev; 159 + int offset = doe_mb->cap_offset; 160 + size_t length, payload_length; 161 + u32 val; 162 + int i; 163 + 164 + /* Read the first dword to get the protocol */ 165 + pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); 166 + if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) || 167 + (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) { 168 + dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n", 169 + doe_mb->cap_offset, task->prot.vid, task->prot.type, 170 + FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val), 171 + FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val)); 172 + return -EIO; 173 + } 174 + 175 + pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); 176 + /* Read the second dword to get the length */ 177 + pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); 178 + pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); 179 + 180 + length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val); 181 + if (length > SZ_1M || length < 2) 182 + return -EIO; 183 + 184 + /* First 2 dwords have already been read */ 185 + length -= 2; 186 + payload_length = min(length, task->response_pl_sz / sizeof(u32)); 187 + /* Read the rest of the response payload */ 188 + for (i = 0; i < payload_length; i++) { 189 + pci_read_config_dword(pdev, offset + PCI_DOE_READ, 190 + &task->response_pl[i]); 191 + /* Prior to the last ack, ensure Data Object Ready */ 192 + if (i == (payload_length - 1) && !pci_doe_data_obj_ready(doe_mb)) 193 + return -EIO; 194 + pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); 195 + } 196 + 197 + /* Flush excess length */ 198 + for (; i < length; i++) { 199 + pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val); 200 + pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0); 201 + } 202 + 203 + /* Final error check to pick up on any since Data Object Ready */ 204 + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); 205 + if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) 206 + return -EIO; 207 + 208 + return min(length, task->response_pl_sz / sizeof(u32)) * sizeof(u32); 209 + } 210 + 211 + static void signal_task_complete(struct pci_doe_task *task, int rv) 212 + { 213 + task->rv = rv; 214 + task->complete(task); 215 + } 216 + 217 + static void signal_task_abort(struct pci_doe_task *task, int rv) 218 + { 219 + struct pci_doe_mb *doe_mb = task->doe_mb; 220 + struct pci_dev *pdev = doe_mb->pdev; 221 + 222 + if (pci_doe_abort(doe_mb)) { 223 + /* 224 + * If the device can't process an abort; set the mailbox dead 225 + * - no more submissions 226 + */ 227 + pci_err(pdev, "[%x] Abort failed marking mailbox dead\n", 228 + doe_mb->cap_offset); 229 + set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags); 230 + } 231 + signal_task_complete(task, rv); 232 + } 233 + 234 + static void doe_statemachine_work(struct work_struct *work) 235 + { 236 + struct pci_doe_task *task = container_of(work, struct pci_doe_task, 237 + work); 238 + struct pci_doe_mb *doe_mb = task->doe_mb; 239 + struct pci_dev *pdev = doe_mb->pdev; 240 + int offset = doe_mb->cap_offset; 241 + unsigned long timeout_jiffies; 242 + u32 val; 243 + int rc; 244 + 245 + if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) { 246 + signal_task_complete(task, -EIO); 247 + return; 248 + } 249 + 250 + /* Send request */ 251 + rc = pci_doe_send_req(doe_mb, task); 252 + if (rc) { 253 + /* 254 + * The specification does not provide any guidance on how to 255 + * resolve conflicting requests from other entities. 256 + * Furthermore, it is likely that busy will not be detected 257 + * most of the time. Flag any detection of status busy with an 258 + * error. 259 + */ 260 + if (rc == -EBUSY) 261 + dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n", 262 + offset); 263 + signal_task_abort(task, rc); 264 + return; 265 + } 266 + 267 + timeout_jiffies = jiffies + PCI_DOE_TIMEOUT; 268 + /* Poll for response */ 269 + retry_resp: 270 + pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val); 271 + if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) { 272 + signal_task_abort(task, -EIO); 273 + return; 274 + } 275 + 276 + if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) { 277 + if (time_after(jiffies, timeout_jiffies)) { 278 + signal_task_abort(task, -EIO); 279 + return; 280 + } 281 + rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL); 282 + if (rc) { 283 + signal_task_abort(task, rc); 284 + return; 285 + } 286 + goto retry_resp; 287 + } 288 + 289 + rc = pci_doe_recv_resp(doe_mb, task); 290 + if (rc < 0) { 291 + signal_task_abort(task, rc); 292 + return; 293 + } 294 + 295 + signal_task_complete(task, rc); 296 + } 297 + 298 + static void pci_doe_task_complete(struct pci_doe_task *task) 299 + { 300 + complete(task->private); 301 + } 302 + 303 + static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid, 304 + u8 *protocol) 305 + { 306 + u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX, 307 + *index); 308 + u32 response_pl; 309 + DECLARE_COMPLETION_ONSTACK(c); 310 + struct pci_doe_task task = { 311 + .prot.vid = PCI_VENDOR_ID_PCI_SIG, 312 + .prot.type = PCI_DOE_PROTOCOL_DISCOVERY, 313 + .request_pl = &request_pl, 314 + .request_pl_sz = sizeof(request_pl), 315 + .response_pl = &response_pl, 316 + .response_pl_sz = sizeof(response_pl), 317 + .complete = pci_doe_task_complete, 318 + .private = &c, 319 + }; 320 + int rc; 321 + 322 + rc = pci_doe_submit_task(doe_mb, &task); 323 + if (rc < 0) 324 + return rc; 325 + 326 + wait_for_completion(&c); 327 + 328 + if (task.rv != sizeof(response_pl)) 329 + return -EIO; 330 + 331 + *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl); 332 + *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL, 333 + response_pl); 334 + *index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX, 335 + response_pl); 336 + 337 + return 0; 338 + } 339 + 340 + static void *pci_doe_xa_prot_entry(u16 vid, u8 prot) 341 + { 342 + return xa_mk_value((vid << 8) | prot); 343 + } 344 + 345 + static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb) 346 + { 347 + u8 index = 0; 348 + u8 xa_idx = 0; 349 + 350 + do { 351 + int rc; 352 + u16 vid; 353 + u8 prot; 354 + 355 + rc = pci_doe_discovery(doe_mb, &index, &vid, &prot); 356 + if (rc) 357 + return rc; 358 + 359 + pci_dbg(doe_mb->pdev, 360 + "[%x] Found protocol %d vid: %x prot: %x\n", 361 + doe_mb->cap_offset, xa_idx, vid, prot); 362 + 363 + rc = xa_insert(&doe_mb->prots, xa_idx++, 364 + pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL); 365 + if (rc) 366 + return rc; 367 + } while (index); 368 + 369 + return 0; 370 + } 371 + 372 + static void pci_doe_xa_destroy(void *mb) 373 + { 374 + struct pci_doe_mb *doe_mb = mb; 375 + 376 + xa_destroy(&doe_mb->prots); 377 + } 378 + 379 + static void pci_doe_destroy_workqueue(void *mb) 380 + { 381 + struct pci_doe_mb *doe_mb = mb; 382 + 383 + destroy_workqueue(doe_mb->work_queue); 384 + } 385 + 386 + static void pci_doe_flush_mb(void *mb) 387 + { 388 + struct pci_doe_mb *doe_mb = mb; 389 + 390 + /* Stop all pending work items from starting */ 391 + set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags); 392 + 393 + /* Cancel an in progress work item, if necessary */ 394 + set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags); 395 + wake_up(&doe_mb->wq); 396 + 397 + /* Flush all work items */ 398 + flush_workqueue(doe_mb->work_queue); 399 + } 400 + 401 + /** 402 + * pcim_doe_create_mb() - Create a DOE mailbox object 403 + * 404 + * @pdev: PCI device to create the DOE mailbox for 405 + * @cap_offset: Offset of the DOE mailbox 406 + * 407 + * Create a single mailbox object to manage the mailbox protocol at the 408 + * cap_offset specified. 409 + * 410 + * RETURNS: created mailbox object on success 411 + * ERR_PTR(-errno) on failure 412 + */ 413 + struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset) 414 + { 415 + struct pci_doe_mb *doe_mb; 416 + struct device *dev = &pdev->dev; 417 + int rc; 418 + 419 + doe_mb = devm_kzalloc(dev, sizeof(*doe_mb), GFP_KERNEL); 420 + if (!doe_mb) 421 + return ERR_PTR(-ENOMEM); 422 + 423 + doe_mb->pdev = pdev; 424 + doe_mb->cap_offset = cap_offset; 425 + init_waitqueue_head(&doe_mb->wq); 426 + 427 + xa_init(&doe_mb->prots); 428 + rc = devm_add_action(dev, pci_doe_xa_destroy, doe_mb); 429 + if (rc) 430 + return ERR_PTR(rc); 431 + 432 + doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0, 433 + dev_driver_string(&pdev->dev), 434 + pci_name(pdev), 435 + doe_mb->cap_offset); 436 + if (!doe_mb->work_queue) { 437 + pci_err(pdev, "[%x] failed to allocate work queue\n", 438 + doe_mb->cap_offset); 439 + return ERR_PTR(-ENOMEM); 440 + } 441 + rc = devm_add_action_or_reset(dev, pci_doe_destroy_workqueue, doe_mb); 442 + if (rc) 443 + return ERR_PTR(rc); 444 + 445 + /* Reset the mailbox by issuing an abort */ 446 + rc = pci_doe_abort(doe_mb); 447 + if (rc) { 448 + pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n", 449 + doe_mb->cap_offset, rc); 450 + return ERR_PTR(rc); 451 + } 452 + 453 + /* 454 + * The state machine and the mailbox should be in sync now; 455 + * Set up mailbox flush prior to using the mailbox to query protocols. 456 + */ 457 + rc = devm_add_action_or_reset(dev, pci_doe_flush_mb, doe_mb); 458 + if (rc) 459 + return ERR_PTR(rc); 460 + 461 + rc = pci_doe_cache_protocols(doe_mb); 462 + if (rc) { 463 + pci_err(pdev, "[%x] failed to cache protocols : %d\n", 464 + doe_mb->cap_offset, rc); 465 + return ERR_PTR(rc); 466 + } 467 + 468 + return doe_mb; 469 + } 470 + EXPORT_SYMBOL_GPL(pcim_doe_create_mb); 471 + 472 + /** 473 + * pci_doe_supports_prot() - Return if the DOE instance supports the given 474 + * protocol 475 + * @doe_mb: DOE mailbox capability to query 476 + * @vid: Protocol Vendor ID 477 + * @type: Protocol type 478 + * 479 + * RETURNS: True if the DOE mailbox supports the protocol specified 480 + */ 481 + bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type) 482 + { 483 + unsigned long index; 484 + void *entry; 485 + 486 + /* The discovery protocol must always be supported */ 487 + if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY) 488 + return true; 489 + 490 + xa_for_each(&doe_mb->prots, index, entry) 491 + if (entry == pci_doe_xa_prot_entry(vid, type)) 492 + return true; 493 + 494 + return false; 495 + } 496 + EXPORT_SYMBOL_GPL(pci_doe_supports_prot); 497 + 498 + /** 499 + * pci_doe_submit_task() - Submit a task to be processed by the state machine 500 + * 501 + * @doe_mb: DOE mailbox capability to submit to 502 + * @task: task to be queued 503 + * 504 + * Submit a DOE task (request/response) to the DOE mailbox to be processed. 505 + * Returns upon queueing the task object. If the queue is full this function 506 + * will sleep until there is room in the queue. 507 + * 508 + * task->complete will be called when the state machine is done processing this 509 + * task. 510 + * 511 + * Excess data will be discarded. 512 + * 513 + * RETURNS: 0 when task has been successfully queued, -ERRNO on error 514 + */ 515 + int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) 516 + { 517 + if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type)) 518 + return -EINVAL; 519 + 520 + /* 521 + * DOE requests must be a whole number of DW and the response needs to 522 + * be big enough for at least 1 DW 523 + */ 524 + if (task->request_pl_sz % sizeof(u32) || 525 + task->response_pl_sz < sizeof(u32)) 526 + return -EINVAL; 527 + 528 + if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) 529 + return -EIO; 530 + 531 + task->doe_mb = doe_mb; 532 + INIT_WORK(&task->work, doe_statemachine_work); 533 + queue_work(doe_mb->work_queue, &task->work); 534 + return 0; 535 + } 536 + EXPORT_SYMBOL_GPL(pci_doe_submit_task);
+1 -1
drivers/pci/probe.c
··· 2315 2315 2316 2316 static bool pci_bus_crs_vendor_id(u32 l) 2317 2317 { 2318 - return (l & 0xffff) == 0x0001; 2318 + return (l & 0xffff) == PCI_VENDOR_ID_PCI_SIG; 2319 2319 } 2320 2320 2321 2321 static bool pci_bus_wait_crs(struct pci_bus *bus, int devfn, u32 *l,
+3
include/linux/ioport.h
··· 141 141 IORES_DESC_DEVICE_PRIVATE_MEMORY = 6, 142 142 IORES_DESC_RESERVED = 7, 143 143 IORES_DESC_SOFT_RESERVED = 8, 144 + IORES_DESC_CXL = 9, 144 145 }; 145 146 146 147 /* ··· 330 329 struct resource *base, unsigned long size); 331 330 struct resource *request_free_mem_region(struct resource *base, 332 331 unsigned long size, const char *name); 332 + struct resource *alloc_free_mem_region(struct resource *base, 333 + unsigned long size, unsigned long align, const char *name); 333 334 334 335 static inline void irqresource_disabled(struct resource *res, u32 irq) 335 336 {
+5
include/linux/libnvdimm.h
··· 59 59 /* Platform provides asynchronous flush mechanism */ 60 60 ND_REGION_ASYNC = 3, 61 61 62 + /* Region was created by CXL subsystem */ 63 + ND_REGION_CXL = 4, 64 + 62 65 /* mark newly adjusted resources as requiring a label update */ 63 66 DPA_RESOURCE_ADJUSTED = 1 << 0, 64 67 }; ··· 125 122 int numa_node; 126 123 int target_node; 127 124 unsigned long flags; 125 + int memregion; 128 126 struct device_node *of_node; 129 127 int (*flush)(struct nd_region *nd_region, struct bio *bio); 130 128 }; ··· 263 259 cmd_mask, num_flush, flush_wpq, NULL, NULL, NULL); 264 260 } 265 261 void nvdimm_delete(struct nvdimm *nvdimm); 262 + void nvdimm_region_delete(struct nd_region *nd_region); 266 263 267 264 const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd); 268 265 const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd);
+77
include/linux/pci-doe.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Data Object Exchange 4 + * PCIe r6.0, sec 6.30 DOE 5 + * 6 + * Copyright (C) 2021 Huawei 7 + * Jonathan Cameron <Jonathan.Cameron@huawei.com> 8 + * 9 + * Copyright (C) 2022 Intel Corporation 10 + * Ira Weiny <ira.weiny@intel.com> 11 + */ 12 + 13 + #ifndef LINUX_PCI_DOE_H 14 + #define LINUX_PCI_DOE_H 15 + 16 + struct pci_doe_protocol { 17 + u16 vid; 18 + u8 type; 19 + }; 20 + 21 + struct pci_doe_mb; 22 + 23 + /** 24 + * struct pci_doe_task - represents a single query/response 25 + * 26 + * @prot: DOE Protocol 27 + * @request_pl: The request payload 28 + * @request_pl_sz: Size of the request payload (bytes) 29 + * @response_pl: The response payload 30 + * @response_pl_sz: Size of the response payload (bytes) 31 + * @rv: Return value. Length of received response or error (bytes) 32 + * @complete: Called when task is complete 33 + * @private: Private data for the consumer 34 + * @work: Used internally by the mailbox 35 + * @doe_mb: Used internally by the mailbox 36 + * 37 + * The payload sizes and rv are specified in bytes with the following 38 + * restrictions concerning the protocol. 39 + * 40 + * 1) The request_pl_sz must be a multiple of double words (4 bytes) 41 + * 2) The response_pl_sz must be >= a single double word (4 bytes) 42 + * 3) rv is returned as bytes but it will be a multiple of double words 43 + * 44 + * NOTE there is no need for the caller to initialize work or doe_mb. 45 + */ 46 + struct pci_doe_task { 47 + struct pci_doe_protocol prot; 48 + u32 *request_pl; 49 + size_t request_pl_sz; 50 + u32 *response_pl; 51 + size_t response_pl_sz; 52 + int rv; 53 + void (*complete)(struct pci_doe_task *task); 54 + void *private; 55 + 56 + /* No need for the user to initialize these fields */ 57 + struct work_struct work; 58 + struct pci_doe_mb *doe_mb; 59 + }; 60 + 61 + /** 62 + * pci_doe_for_each_off - Iterate each DOE capability 63 + * @pdev: struct pci_dev to iterate 64 + * @off: u16 of config space offset of each mailbox capability found 65 + */ 66 + #define pci_doe_for_each_off(pdev, off) \ 67 + for (off = pci_find_next_ext_capability(pdev, off, \ 68 + PCI_EXT_CAP_ID_DOE); \ 69 + off > 0; \ 70 + off = pci_find_next_ext_capability(pdev, off, \ 71 + PCI_EXT_CAP_ID_DOE)) 72 + 73 + struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset); 74 + bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type); 75 + int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task); 76 + 77 + #endif
+1
include/linux/pci_ids.h
··· 151 151 #define PCI_CLASS_OTHERS 0xff 152 152 153 153 /* Vendors and devices. Sort key: vendor first, device next. */ 154 + #define PCI_VENDOR_ID_PCI_SIG 0x0001 154 155 155 156 #define PCI_VENDOR_ID_LOONGSON 0x0014 156 157
+16
include/linux/sysfs.h
··· 235 235 #define BIN_ATTR_RW(_name, _size) \ 236 236 struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size) 237 237 238 + 239 + #define __BIN_ATTR_ADMIN_RO(_name, _size) { \ 240 + .attr = { .name = __stringify(_name), .mode = 0400 }, \ 241 + .read = _name##_read, \ 242 + .size = _size, \ 243 + } 244 + 245 + #define __BIN_ATTR_ADMIN_RW(_name, _size) \ 246 + __BIN_ATTR(_name, 0600, _name##_read, _name##_write, _size) 247 + 248 + #define BIN_ATTR_ADMIN_RO(_name, _size) \ 249 + struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RO(_name, _size) 250 + 251 + #define BIN_ATTR_ADMIN_RW(_name, _size) \ 252 + struct bin_attribute bin_attr_##_name = __BIN_ATTR_ADMIN_RW(_name, _size) 253 + 238 254 struct sysfs_ops { 239 255 ssize_t (*show)(struct kobject *, struct attribute *, char *); 240 256 ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
+28 -1
include/uapi/linux/pci_regs.h
··· 737 737 #define PCI_EXT_CAP_ID_DVSEC 0x23 /* Designated Vendor-Specific */ 738 738 #define PCI_EXT_CAP_ID_DLF 0x25 /* Data Link Feature */ 739 739 #define PCI_EXT_CAP_ID_PL_16GT 0x26 /* Physical Layer 16.0 GT/s */ 740 - #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_16GT 740 + #define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */ 741 + #define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE 741 742 742 743 #define PCI_EXT_CAP_DSN_SIZEOF 12 743 744 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 ··· 1103 1102 #define PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK 0x0000000F 1104 1103 #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0 1105 1104 #define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4 1105 + 1106 + /* Data Object Exchange */ 1107 + #define PCI_DOE_CAP 0x04 /* DOE Capabilities Register */ 1108 + #define PCI_DOE_CAP_INT_SUP 0x00000001 /* Interrupt Support */ 1109 + #define PCI_DOE_CAP_INT_MSG_NUM 0x00000ffe /* Interrupt Message Number */ 1110 + #define PCI_DOE_CTRL 0x08 /* DOE Control Register */ 1111 + #define PCI_DOE_CTRL_ABORT 0x00000001 /* DOE Abort */ 1112 + #define PCI_DOE_CTRL_INT_EN 0x00000002 /* DOE Interrupt Enable */ 1113 + #define PCI_DOE_CTRL_GO 0x80000000 /* DOE Go */ 1114 + #define PCI_DOE_STATUS 0x0c /* DOE Status Register */ 1115 + #define PCI_DOE_STATUS_BUSY 0x00000001 /* DOE Busy */ 1116 + #define PCI_DOE_STATUS_INT_STATUS 0x00000002 /* DOE Interrupt Status */ 1117 + #define PCI_DOE_STATUS_ERROR 0x00000004 /* DOE Error */ 1118 + #define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */ 1119 + #define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */ 1120 + #define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */ 1121 + 1122 + /* DOE Data Object - note not actually registers */ 1123 + #define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff 1124 + #define PCI_DOE_DATA_OBJECT_HEADER_1_TYPE 0x00ff0000 1125 + #define PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH 0x0003ffff 1126 + 1127 + #define PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX 0x000000ff 1128 + #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID 0x0000ffff 1129 + #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL 0x00ff0000 1130 + #define PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX 0xff000000 1106 1131 1107 1132 #endif /* LINUX_PCI_REGS_H */
+150 -35
kernel/resource.c
··· 489 489 } 490 490 EXPORT_SYMBOL_GPL(page_is_ram); 491 491 492 - static int __region_intersects(resource_size_t start, size_t size, 493 - unsigned long flags, unsigned long desc) 492 + static int __region_intersects(struct resource *parent, resource_size_t start, 493 + size_t size, unsigned long flags, 494 + unsigned long desc) 494 495 { 495 496 struct resource res; 496 497 int type = 0; int other = 0; ··· 500 499 res.start = start; 501 500 res.end = start + size - 1; 502 501 503 - for (p = iomem_resource.child; p ; p = p->sibling) { 502 + for (p = parent->child; p ; p = p->sibling) { 504 503 bool is_type = (((p->flags & flags) == flags) && 505 504 ((desc == IORES_DESC_NONE) || 506 505 (desc == p->desc))); ··· 544 543 int ret; 545 544 546 545 read_lock(&resource_lock); 547 - ret = __region_intersects(start, size, flags, desc); 546 + ret = __region_intersects(&iomem_resource, start, size, flags, desc); 548 547 read_unlock(&resource_lock); 549 548 550 549 return ret; ··· 892 891 } 893 892 write_unlock(&resource_lock); 894 893 } 894 + /* 895 + * Not for general consumption, only early boot memory map parsing, PCI 896 + * resource discovery, and late discovery of CXL resources are expected 897 + * to use this interface. The former are built-in and only the latter, 898 + * CXL, is a module. 899 + */ 900 + EXPORT_SYMBOL_NS_GPL(insert_resource_expand_to_fit, CXL); 895 901 896 902 /** 897 903 * remove_resource - Remove a resource in the resource tree ··· 1781 1773 } 1782 1774 EXPORT_SYMBOL(resource_list_free); 1783 1775 1784 - #ifdef CONFIG_DEVICE_PRIVATE 1785 - static struct resource *__request_free_mem_region(struct device *dev, 1786 - struct resource *base, unsigned long size, const char *name) 1776 + #ifdef CONFIG_GET_FREE_REGION 1777 + #define GFR_DESCENDING (1UL << 0) 1778 + #define GFR_REQUEST_REGION (1UL << 1) 1779 + #define GFR_DEFAULT_ALIGN (1UL << PA_SECTION_SHIFT) 1780 + 1781 + static resource_size_t gfr_start(struct resource *base, resource_size_t size, 1782 + resource_size_t align, unsigned long flags) 1787 1783 { 1788 - resource_size_t end, addr; 1784 + if (flags & GFR_DESCENDING) { 1785 + resource_size_t end; 1786 + 1787 + end = min_t(resource_size_t, base->end, 1788 + (1ULL << MAX_PHYSMEM_BITS) - 1); 1789 + return end - size + 1; 1790 + } 1791 + 1792 + return ALIGN(base->start, align); 1793 + } 1794 + 1795 + static bool gfr_continue(struct resource *base, resource_size_t addr, 1796 + resource_size_t size, unsigned long flags) 1797 + { 1798 + if (flags & GFR_DESCENDING) 1799 + return addr > size && addr >= base->start; 1800 + /* 1801 + * In the ascend case be careful that the last increment by 1802 + * @size did not wrap 0. 1803 + */ 1804 + return addr > addr - size && 1805 + addr <= min_t(resource_size_t, base->end, 1806 + (1ULL << MAX_PHYSMEM_BITS) - 1); 1807 + } 1808 + 1809 + static resource_size_t gfr_next(resource_size_t addr, resource_size_t size, 1810 + unsigned long flags) 1811 + { 1812 + if (flags & GFR_DESCENDING) 1813 + return addr - size; 1814 + return addr + size; 1815 + } 1816 + 1817 + static void remove_free_mem_region(void *_res) 1818 + { 1819 + struct resource *res = _res; 1820 + 1821 + if (res->parent) 1822 + remove_resource(res); 1823 + free_resource(res); 1824 + } 1825 + 1826 + static struct resource * 1827 + get_free_mem_region(struct device *dev, struct resource *base, 1828 + resource_size_t size, const unsigned long align, 1829 + const char *name, const unsigned long desc, 1830 + const unsigned long flags) 1831 + { 1832 + resource_size_t addr; 1789 1833 struct resource *res; 1790 1834 struct region_devres *dr = NULL; 1791 1835 1792 - size = ALIGN(size, 1UL << PA_SECTION_SHIFT); 1793 - end = min_t(unsigned long, base->end, (1UL << MAX_PHYSMEM_BITS) - 1); 1794 - addr = end - size + 1UL; 1836 + size = ALIGN(size, align); 1795 1837 1796 1838 res = alloc_resource(GFP_KERNEL); 1797 1839 if (!res) 1798 1840 return ERR_PTR(-ENOMEM); 1799 1841 1800 - if (dev) { 1842 + if (dev && (flags & GFR_REQUEST_REGION)) { 1801 1843 dr = devres_alloc(devm_region_release, 1802 1844 sizeof(struct region_devres), GFP_KERNEL); 1803 1845 if (!dr) { 1804 1846 free_resource(res); 1805 1847 return ERR_PTR(-ENOMEM); 1806 1848 } 1849 + } else if (dev) { 1850 + if (devm_add_action_or_reset(dev, remove_free_mem_region, res)) 1851 + return ERR_PTR(-ENOMEM); 1807 1852 } 1808 1853 1809 1854 write_lock(&resource_lock); 1810 - for (; addr > size && addr >= base->start; addr -= size) { 1811 - if (__region_intersects(addr, size, 0, IORES_DESC_NONE) != 1812 - REGION_DISJOINT) 1855 + for (addr = gfr_start(base, size, align, flags); 1856 + gfr_continue(base, addr, size, flags); 1857 + addr = gfr_next(addr, size, flags)) { 1858 + if (__region_intersects(base, addr, size, 0, IORES_DESC_NONE) != 1859 + REGION_DISJOINT) 1813 1860 continue; 1814 1861 1815 - if (__request_region_locked(res, &iomem_resource, addr, size, 1816 - name, 0)) 1817 - break; 1862 + if (flags & GFR_REQUEST_REGION) { 1863 + if (__request_region_locked(res, &iomem_resource, addr, 1864 + size, name, 0)) 1865 + break; 1818 1866 1819 - if (dev) { 1820 - dr->parent = &iomem_resource; 1821 - dr->start = addr; 1822 - dr->n = size; 1823 - devres_add(dev, dr); 1867 + if (dev) { 1868 + dr->parent = &iomem_resource; 1869 + dr->start = addr; 1870 + dr->n = size; 1871 + devres_add(dev, dr); 1872 + } 1873 + 1874 + res->desc = desc; 1875 + write_unlock(&resource_lock); 1876 + 1877 + 1878 + /* 1879 + * A driver is claiming this region so revoke any 1880 + * mappings. 1881 + */ 1882 + revoke_iomem(res); 1883 + } else { 1884 + res->start = addr; 1885 + res->end = addr + size - 1; 1886 + res->name = name; 1887 + res->desc = desc; 1888 + res->flags = IORESOURCE_MEM; 1889 + 1890 + /* 1891 + * Only succeed if the resource hosts an exclusive 1892 + * range after the insert 1893 + */ 1894 + if (__insert_resource(base, res) || res->child) 1895 + break; 1896 + 1897 + write_unlock(&resource_lock); 1824 1898 } 1825 1899 1826 - res->desc = IORES_DESC_DEVICE_PRIVATE_MEMORY; 1827 - write_unlock(&resource_lock); 1828 - 1829 - /* 1830 - * A driver is claiming this region so revoke any mappings. 1831 - */ 1832 - revoke_iomem(res); 1833 1900 return res; 1834 1901 } 1835 1902 write_unlock(&resource_lock); 1836 1903 1837 - free_resource(res); 1838 - if (dr) 1904 + if (flags & GFR_REQUEST_REGION) { 1905 + free_resource(res); 1839 1906 devres_free(dr); 1907 + } else if (dev) 1908 + devm_release_action(dev, remove_free_mem_region, res); 1840 1909 1841 1910 return ERR_PTR(-ERANGE); 1842 1911 } ··· 1932 1847 struct resource *devm_request_free_mem_region(struct device *dev, 1933 1848 struct resource *base, unsigned long size) 1934 1849 { 1935 - return __request_free_mem_region(dev, base, size, dev_name(dev)); 1850 + unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION; 1851 + 1852 + return get_free_mem_region(dev, base, size, GFR_DEFAULT_ALIGN, 1853 + dev_name(dev), 1854 + IORES_DESC_DEVICE_PRIVATE_MEMORY, flags); 1936 1855 } 1937 1856 EXPORT_SYMBOL_GPL(devm_request_free_mem_region); 1938 1857 1939 1858 struct resource *request_free_mem_region(struct resource *base, 1940 1859 unsigned long size, const char *name) 1941 1860 { 1942 - return __request_free_mem_region(NULL, base, size, name); 1861 + unsigned long flags = GFR_DESCENDING | GFR_REQUEST_REGION; 1862 + 1863 + return get_free_mem_region(NULL, base, size, GFR_DEFAULT_ALIGN, name, 1864 + IORES_DESC_DEVICE_PRIVATE_MEMORY, flags); 1943 1865 } 1944 1866 EXPORT_SYMBOL_GPL(request_free_mem_region); 1945 1867 1946 - #endif /* CONFIG_DEVICE_PRIVATE */ 1868 + /** 1869 + * alloc_free_mem_region - find a free region relative to @base 1870 + * @base: resource that will parent the new resource 1871 + * @size: size in bytes of memory to allocate from @base 1872 + * @align: alignment requirements for the allocation 1873 + * @name: resource name 1874 + * 1875 + * Buses like CXL, that can dynamically instantiate new memory regions, 1876 + * need a method to allocate physical address space for those regions. 1877 + * Allocate and insert a new resource to cover a free, unclaimed by a 1878 + * descendant of @base, range in the span of @base. 1879 + */ 1880 + struct resource *alloc_free_mem_region(struct resource *base, 1881 + unsigned long size, unsigned long align, 1882 + const char *name) 1883 + { 1884 + /* Default of ascending direction and insert resource */ 1885 + unsigned long flags = 0; 1886 + 1887 + return get_free_mem_region(NULL, base, size, align, name, 1888 + IORES_DESC_NONE, flags); 1889 + } 1890 + EXPORT_SYMBOL_NS_GPL(alloc_free_mem_region, CXL); 1891 + #endif /* CONFIG_GET_FREE_REGION */ 1947 1892 1948 1893 static int __init strict_iomem(char *str) 1949 1894 {
+5
mm/Kconfig
··· 983 983 bool 984 984 depends on MMU 985 985 986 + config GET_FREE_REGION 987 + depends on SPARSEMEM 988 + bool 989 + 986 990 config DEVICE_PRIVATE 987 991 bool "Unaddressable device memory (GPU memory, ...)" 988 992 depends on ZONE_DEVICE 993 + select GET_FREE_REGION 989 994 990 995 help 991 996 Allows creation of struct pages to represent unaddressable device
+1
tools/testing/cxl/Kbuild
··· 47 47 cxl_core-y += $(CXL_CORE_SRC)/mbox.o 48 48 cxl_core-y += $(CXL_CORE_SRC)/pci.o 49 49 cxl_core-y += $(CXL_CORE_SRC)/hdm.o 50 + cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o 50 51 cxl_core-y += config_check.o 51 52 52 53 obj-m += test/
+76 -55
tools/testing/cxl/test/cxl.c
··· 14 14 #define NR_CXL_HOST_BRIDGES 2 15 15 #define NR_CXL_ROOT_PORTS 2 16 16 #define NR_CXL_SWITCH_PORTS 2 17 - #define NR_CXL_PORT_DECODERS 2 17 + #define NR_CXL_PORT_DECODERS 8 18 18 19 19 static struct platform_device *cxl_acpi; 20 20 static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES]; ··· 118 118 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 119 119 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, 120 120 .qtg_id = 0, 121 - .window_size = SZ_256M, 121 + .window_size = SZ_256M * 4UL, 122 122 }, 123 123 .target = { 0 }, 124 124 }, ··· 133 133 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 134 134 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE, 135 135 .qtg_id = 1, 136 - .window_size = SZ_256M * 2, 136 + .window_size = SZ_256M * 8UL, 137 137 }, 138 138 .target = { 0, 1, }, 139 139 }, ··· 148 148 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 149 149 ACPI_CEDT_CFMWS_RESTRICT_PMEM, 150 150 .qtg_id = 2, 151 - .window_size = SZ_256M, 151 + .window_size = SZ_256M * 4UL, 152 152 }, 153 153 .target = { 0 }, 154 154 }, ··· 163 163 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 | 164 164 ACPI_CEDT_CFMWS_RESTRICT_PMEM, 165 165 .qtg_id = 3, 166 - .window_size = SZ_256M * 2, 166 + .window_size = SZ_256M * 8UL, 167 167 }, 168 168 .target = { 0, 1, }, 169 169 }, ··· 429 429 return 0; 430 430 } 431 431 432 + static int mock_decoder_commit(struct cxl_decoder *cxld) 433 + { 434 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 435 + int id = cxld->id; 436 + 437 + if (cxld->flags & CXL_DECODER_F_ENABLE) 438 + return 0; 439 + 440 + dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev)); 441 + if (port->commit_end + 1 != id) { 442 + dev_dbg(&port->dev, 443 + "%s: out of order commit, expected decoder%d.%d\n", 444 + dev_name(&cxld->dev), port->id, port->commit_end + 1); 445 + return -EBUSY; 446 + } 447 + 448 + port->commit_end++; 449 + cxld->flags |= CXL_DECODER_F_ENABLE; 450 + 451 + return 0; 452 + } 453 + 454 + static int mock_decoder_reset(struct cxl_decoder *cxld) 455 + { 456 + struct cxl_port *port = to_cxl_port(cxld->dev.parent); 457 + int id = cxld->id; 458 + 459 + if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0) 460 + return 0; 461 + 462 + dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev)); 463 + if (port->commit_end != id) { 464 + dev_dbg(&port->dev, 465 + "%s: out of order reset, expected decoder%d.%d\n", 466 + dev_name(&cxld->dev), port->id, port->commit_end); 467 + return -EBUSY; 468 + } 469 + 470 + port->commit_end--; 471 + cxld->flags &= ~CXL_DECODER_F_ENABLE; 472 + 473 + return 0; 474 + } 475 + 432 476 static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm) 433 477 { 434 478 struct cxl_port *port = cxlhdm->port; ··· 495 451 struct cxl_decoder *cxld; 496 452 int rc; 497 453 498 - if (target_count) 499 - cxld = cxl_switch_decoder_alloc(port, target_count); 500 - else 501 - cxld = cxl_endpoint_decoder_alloc(port); 502 - if (IS_ERR(cxld)) { 503 - dev_warn(&port->dev, 504 - "Failed to allocate the decoder\n"); 505 - return PTR_ERR(cxld); 454 + if (target_count) { 455 + struct cxl_switch_decoder *cxlsd; 456 + 457 + cxlsd = cxl_switch_decoder_alloc(port, target_count); 458 + if (IS_ERR(cxlsd)) { 459 + dev_warn(&port->dev, 460 + "Failed to allocate the decoder\n"); 461 + return PTR_ERR(cxlsd); 462 + } 463 + cxld = &cxlsd->cxld; 464 + } else { 465 + struct cxl_endpoint_decoder *cxled; 466 + 467 + cxled = cxl_endpoint_decoder_alloc(port); 468 + 469 + if (IS_ERR(cxled)) { 470 + dev_warn(&port->dev, 471 + "Failed to allocate the decoder\n"); 472 + return PTR_ERR(cxled); 473 + } 474 + cxld = &cxled->cxld; 506 475 } 507 476 508 - cxld->decoder_range = (struct range) { 477 + cxld->hpa_range = (struct range) { 509 478 .start = 0, 510 479 .end = -1, 511 480 }; 512 481 513 - cxld->flags = CXL_DECODER_F_ENABLE; 514 482 cxld->interleave_ways = min_not_zero(target_count, 1); 515 483 cxld->interleave_granularity = SZ_4K; 516 484 cxld->target_type = CXL_DECODER_EXPANDER; 485 + cxld->commit = mock_decoder_commit; 486 + cxld->reset = mock_decoder_reset; 517 487 518 488 if (target_count) { 519 489 rc = device_for_each_child(port->uport, &ctx, ··· 627 569 #define SZ_512G (SZ_64G * 8) 628 570 #endif 629 571 630 - static struct platform_device *alloc_memdev(int id) 631 - { 632 - struct resource res[] = { 633 - [0] = { 634 - .flags = IORESOURCE_MEM, 635 - }, 636 - [1] = { 637 - .flags = IORESOURCE_MEM, 638 - .desc = IORES_DESC_PERSISTENT_MEMORY, 639 - }, 640 - }; 641 - struct platform_device *pdev; 642 - int i, rc; 643 - 644 - for (i = 0; i < ARRAY_SIZE(res); i++) { 645 - struct cxl_mock_res *r = alloc_mock_res(SZ_256M); 646 - 647 - if (!r) 648 - return NULL; 649 - res[i].start = r->range.start; 650 - res[i].end = r->range.end; 651 - } 652 - 653 - pdev = platform_device_alloc("cxl_mem", id); 654 - if (!pdev) 655 - return NULL; 656 - 657 - rc = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); 658 - if (rc) 659 - goto err; 660 - 661 - return pdev; 662 - 663 - err: 664 - platform_device_put(pdev); 665 - return NULL; 666 - } 667 - 668 572 static __init int cxl_test_init(void) 669 573 { 670 574 int rc, i; ··· 639 619 goto err_gen_pool_create; 640 620 } 641 621 642 - rc = gen_pool_add(cxl_mock_pool, SZ_512G, SZ_64G, NUMA_NO_NODE); 622 + rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G, 623 + SZ_64G, NUMA_NO_NODE); 643 624 if (rc) 644 625 goto err_gen_pool_add; 645 626 ··· 729 708 struct platform_device *dport = cxl_switch_dport[i]; 730 709 struct platform_device *pdev; 731 710 732 - pdev = alloc_memdev(i); 711 + pdev = platform_device_alloc("cxl_mem", i); 733 712 if (!pdev) 734 713 goto err_mem; 735 714 pdev->dev.parent = &dport->dev;
+31 -28
tools/testing/cxl/test/mem.c
··· 10 10 #include <cxlmem.h> 11 11 12 12 #define LSA_SIZE SZ_128K 13 + #define DEV_SIZE SZ_2G 13 14 #define EFFECT(x) (1U << x) 14 15 15 16 static struct cxl_cel_entry mock_cel[] = { ··· 24 23 }, 25 24 { 26 25 .opcode = cpu_to_le16(CXL_MBOX_OP_GET_LSA), 26 + .effect = cpu_to_le16(0), 27 + }, 28 + { 29 + .opcode = cpu_to_le16(CXL_MBOX_OP_GET_PARTITION_INFO), 27 30 .effect = cpu_to_le16(0), 28 31 }, 29 32 { ··· 102 97 103 98 static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd) 104 99 { 105 - struct platform_device *pdev = to_platform_device(cxlds->dev); 106 100 struct cxl_mbox_identify id = { 107 101 .fw_revision = { "mock fw v1 " }, 108 102 .lsa_size = cpu_to_le32(LSA_SIZE), 109 - /* FIXME: Add partition support */ 110 - .partition_align = cpu_to_le64(0), 103 + .partition_align = 104 + cpu_to_le64(SZ_256M / CXL_CAPACITY_MULTIPLIER), 105 + .total_capacity = 106 + cpu_to_le64(DEV_SIZE / CXL_CAPACITY_MULTIPLIER), 111 107 }; 112 - u64 capacity = 0; 113 - int i; 114 108 115 109 if (cmd->size_out < sizeof(id)) 116 110 return -EINVAL; 117 111 118 - for (i = 0; i < 2; i++) { 119 - struct resource *res; 120 - 121 - res = platform_get_resource(pdev, IORESOURCE_MEM, i); 122 - if (!res) 123 - break; 124 - 125 - capacity += resource_size(res) / CXL_CAPACITY_MULTIPLIER; 126 - 127 - if (le64_to_cpu(id.partition_align)) 128 - continue; 129 - 130 - if (res->desc == IORES_DESC_PERSISTENT_MEMORY) 131 - id.persistent_capacity = cpu_to_le64( 132 - resource_size(res) / CXL_CAPACITY_MULTIPLIER); 133 - else 134 - id.volatile_capacity = cpu_to_le64( 135 - resource_size(res) / CXL_CAPACITY_MULTIPLIER); 136 - } 137 - 138 - id.total_capacity = cpu_to_le64(capacity); 139 - 140 112 memcpy(cmd->payload_out, &id, sizeof(id)); 113 + 114 + return 0; 115 + } 116 + 117 + static int mock_partition_info(struct cxl_dev_state *cxlds, 118 + struct cxl_mbox_cmd *cmd) 119 + { 120 + struct cxl_mbox_get_partition_info pi = { 121 + .active_volatile_cap = 122 + cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 123 + .active_persistent_cap = 124 + cpu_to_le64(DEV_SIZE / 2 / CXL_CAPACITY_MULTIPLIER), 125 + }; 126 + 127 + if (cmd->size_out < sizeof(pi)) 128 + return -EINVAL; 129 + 130 + memcpy(cmd->payload_out, &pi, sizeof(pi)); 141 131 142 132 return 0; 143 133 } ··· 221 221 case CXL_MBOX_OP_GET_LSA: 222 222 rc = mock_get_lsa(cxlds, cmd); 223 223 break; 224 + case CXL_MBOX_OP_GET_PARTITION_INFO: 225 + rc = mock_partition_info(cxlds, cmd); 226 + break; 224 227 case CXL_MBOX_OP_SET_LSA: 225 228 rc = mock_set_lsa(cxlds, cmd); 226 229 break; ··· 285 282 if (IS_ERR(cxlmd)) 286 283 return PTR_ERR(cxlmd); 287 284 288 - if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) 285 + if (resource_size(&cxlds->pmem_res) && IS_ENABLED(CONFIG_CXL_PMEM)) 289 286 rc = devm_cxl_add_nvdimm(dev, cxlmd); 290 287 291 288 return 0;
+5 -3
tools/testing/cxl/test/mock.c
··· 208 208 } 209 209 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, CXL); 210 210 211 - bool __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds, 212 - struct cxl_hdm *cxlhdm) 211 + int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds, 212 + struct cxl_hdm *cxlhdm) 213 213 { 214 214 int rc = 0, index; 215 215 struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 216 216 217 - if (!ops || !ops->is_mock_dev(cxlds->dev)) 217 + if (ops && ops->is_mock_dev(cxlds->dev)) 218 + rc = 0; 219 + else 218 220 rc = cxl_hdm_decode_init(cxlds, cxlhdm); 219 221 put_cxl_mock_ops(index); 220 222