@@ -250,10 +250,152 @@ static ssize_t interleave_granularity_store(struct device *dev,
250250}
251251static DEVICE_ATTR_RW (interleave_granularity );
252252
253+ static ssize_t resource_show (struct device * dev , struct device_attribute * attr ,
254+ char * buf )
255+ {
256+ struct cxl_region * cxlr = to_cxl_region (dev );
257+ struct cxl_region_params * p = & cxlr -> params ;
258+ u64 resource = -1ULL ;
259+ ssize_t rc ;
260+
261+ rc = down_read_interruptible (& cxl_region_rwsem );
262+ if (rc )
263+ return rc ;
264+ if (p -> res )
265+ resource = p -> res -> start ;
266+ rc = sysfs_emit (buf , "%#llx\n" , resource );
267+ up_read (& cxl_region_rwsem );
268+
269+ return rc ;
270+ }
271+ static DEVICE_ATTR_RO (resource );
272+
273+ static int alloc_hpa (struct cxl_region * cxlr , resource_size_t size )
274+ {
275+ struct cxl_root_decoder * cxlrd = to_cxl_root_decoder (cxlr -> dev .parent );
276+ struct cxl_region_params * p = & cxlr -> params ;
277+ struct resource * res ;
278+ u32 remainder = 0 ;
279+
280+ lockdep_assert_held_write (& cxl_region_rwsem );
281+
282+ /* Nothing to do... */
283+ if (p -> res && resource_size (res ) == size )
284+ return 0 ;
285+
286+ /* To change size the old size must be freed first */
287+ if (p -> res )
288+ return - EBUSY ;
289+
290+ if (p -> state >= CXL_CONFIG_INTERLEAVE_ACTIVE )
291+ return - EBUSY ;
292+
293+ /* ways, granularity and uuid (if PMEM) need to be set before HPA */
294+ if (!p -> interleave_ways || !p -> interleave_granularity ||
295+ (cxlr -> mode == CXL_DECODER_PMEM && uuid_is_null (& p -> uuid )))
296+ return - ENXIO ;
297+
298+ div_u64_rem (size , SZ_256M * p -> interleave_ways , & remainder );
299+ if (remainder )
300+ return - EINVAL ;
301+
302+ res = alloc_free_mem_region (cxlrd -> res , size , SZ_256M ,
303+ dev_name (& cxlr -> dev ));
304+ if (IS_ERR (res )) {
305+ dev_dbg (& cxlr -> dev , "failed to allocate HPA: %ld\n" ,
306+ PTR_ERR (res ));
307+ return PTR_ERR (res );
308+ }
309+
310+ p -> res = res ;
311+ p -> state = CXL_CONFIG_INTERLEAVE_ACTIVE ;
312+
313+ return 0 ;
314+ }
315+
316+ static void cxl_region_iomem_release (struct cxl_region * cxlr )
317+ {
318+ struct cxl_region_params * p = & cxlr -> params ;
319+
320+ if (device_is_registered (& cxlr -> dev ))
321+ lockdep_assert_held_write (& cxl_region_rwsem );
322+ if (p -> res ) {
323+ remove_resource (p -> res );
324+ kfree (p -> res );
325+ p -> res = NULL ;
326+ }
327+ }
328+
329+ static int free_hpa (struct cxl_region * cxlr )
330+ {
331+ struct cxl_region_params * p = & cxlr -> params ;
332+
333+ lockdep_assert_held_write (& cxl_region_rwsem );
334+
335+ if (!p -> res )
336+ return 0 ;
337+
338+ if (p -> state >= CXL_CONFIG_ACTIVE )
339+ return - EBUSY ;
340+
341+ cxl_region_iomem_release (cxlr );
342+ p -> state = CXL_CONFIG_IDLE ;
343+ return 0 ;
344+ }
345+
346+ static ssize_t size_store (struct device * dev , struct device_attribute * attr ,
347+ const char * buf , size_t len )
348+ {
349+ struct cxl_region * cxlr = to_cxl_region (dev );
350+ u64 val ;
351+ int rc ;
352+
353+ rc = kstrtou64 (buf , 0 , & val );
354+ if (rc )
355+ return rc ;
356+
357+ rc = down_write_killable (& cxl_region_rwsem );
358+ if (rc )
359+ return rc ;
360+
361+ if (val )
362+ rc = alloc_hpa (cxlr , val );
363+ else
364+ rc = free_hpa (cxlr );
365+ up_write (& cxl_region_rwsem );
366+
367+ if (rc )
368+ return rc ;
369+
370+ return len ;
371+ }
372+
373+ static ssize_t size_show (struct device * dev , struct device_attribute * attr ,
374+ char * buf )
375+ {
376+ struct cxl_region * cxlr = to_cxl_region (dev );
377+ struct cxl_region_params * p = & cxlr -> params ;
378+ u64 size = 0 ;
379+ ssize_t rc ;
380+
381+ rc = down_read_interruptible (& cxl_region_rwsem );
382+ if (rc )
383+ return rc ;
384+ if (p -> res )
385+ size = resource_size (p -> res );
386+ rc = sysfs_emit (buf , "%#llx\n" , size );
387+ up_read (& cxl_region_rwsem );
388+
389+ return rc ;
390+ }
391+ static DEVICE_ATTR_RW (size );
392+
253393static struct attribute * cxl_region_attrs [] = {
254394 & dev_attr_uuid .attr ,
255395 & dev_attr_interleave_ways .attr ,
256396 & dev_attr_interleave_granularity .attr ,
397+ & dev_attr_resource .attr ,
398+ & dev_attr_size .attr ,
257399 NULL ,
258400};
259401
@@ -299,7 +441,11 @@ static struct cxl_region *to_cxl_region(struct device *dev)
299441
300442static void unregister_region (void * dev )
301443{
302- device_unregister (dev );
444+ struct cxl_region * cxlr = to_cxl_region (dev );
445+
446+ device_del (dev );
447+ cxl_region_iomem_release (cxlr );
448+ put_device (dev );
303449}
304450
305451static struct lock_class_key cxl_region_key ;
@@ -451,3 +597,5 @@ static ssize_t delete_region_store(struct device *dev,
451597 return len ;
452598}
453599DEVICE_ATTR_WO (delete_region );
600+
601+ MODULE_IMPORT_NS (CXL );
0 commit comments