2022-02-04 07:18:31 -08:00
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
2022-05-26 12:15:25 -07:00
# include <linux/debugfs.h>
2022-02-04 07:18:31 -08:00
# include <linux/device.h>
# include <linux/module.h>
# include <linux/pci.h>
# include "cxlmem.h"
# include "cxlpci.h"
/**
* DOC : cxl mem
*
* CXL memory endpoint devices and switches are CXL capable devices that are
* participating in CXL . mem protocol . Their functionality builds on top of the
* CXL . io protocol that allows enumerating and configuring components via
* standard PCI mechanisms .
*
* The cxl_mem driver owns kicking off the enumeration of this CXL . mem
* capability . With the detection of a CXL capable endpoint , the driver will
* walk up to find the platform specific port it is connected to , and determine
* if there are intervening switches in the path . If there are switches , a
* secondary action is to enumerate those ( implemented in cxl_core ) . Finally the
* cxl_mem driver adds the device it is bound to as a CXL endpoint - port for use
* in higher level operations .
*/
2022-04-22 15:58:11 -07:00
static void enable_suspend ( void * data )
{
cxl_mem_active_dec ( ) ;
}
2022-05-26 12:15:25 -07:00
static void remove_debugfs ( void * dentry )
{
debugfs_remove_recursive ( dentry ) ;
}
static int cxl_mem_dpa_show ( struct seq_file * file , void * data )
{
struct device * dev = file - > private ;
struct cxl_memdev * cxlmd = to_cxl_memdev ( dev ) ;
cxl_dpa_debug ( file , cxlmd - > cxlds ) ;
return 0 ;
}
2022-02-04 07:18:31 -08:00
static int cxl_mem_probe ( struct device * dev )
{
struct cxl_memdev * cxlmd = to_cxl_memdev ( dev ) ;
struct cxl_port * parent_port ;
2022-05-27 10:57:01 -07:00
struct cxl_dport * dport ;
2022-05-26 12:15:25 -07:00
struct dentry * dentry ;
2022-02-04 07:18:31 -08:00
int rc ;
/*
* Someone is trying to reattach this device after it lost its port
* connection ( an endpoint port previously registered by this memdev was
* disabled ) . This racy check is ok because if the port is still gone ,
* no harm done , and if the port hierarchy comes back it will re - trigger
* this probe . Port rescan and memdev detach work share the same
* single - threaded workqueue .
*/
if ( work_pending ( & cxlmd - > detach_work ) )
return - EBUSY ;
2022-05-26 12:15:25 -07:00
dentry = cxl_debugfs_create_dir ( dev_name ( dev ) ) ;
debugfs_create_devm_seqfile ( dev , " dpamem " , dentry , cxl_mem_dpa_show ) ;
rc = devm_add_action_or_reset ( dev , remove_debugfs , dentry ) ;
if ( rc )
return rc ;
2022-02-04 07:18:31 -08:00
rc = devm_cxl_enumerate_ports ( cxlmd ) ;
if ( rc )
return rc ;
2022-05-27 10:57:01 -07:00
parent_port = cxl_mem_find_port ( cxlmd , & dport ) ;
2022-02-04 07:18:31 -08:00
if ( ! parent_port ) {
dev_err ( dev , " CXL port topology not found \n " ) ;
return - ENXIO ;
}
2022-04-21 08:33:23 -07:00
device_lock ( & parent_port - > dev ) ;
2022-02-04 07:18:31 -08:00
if ( ! parent_port - > dev . driver ) {
dev_err ( dev , " CXL port topology %s not enabled \n " ,
dev_name ( & parent_port - > dev ) ) ;
rc = - ENXIO ;
2022-05-18 16:34:31 -07:00
goto unlock ;
2022-02-04 07:18:31 -08:00
}
2022-06-07 10:35:39 -07:00
rc = devm_cxl_add_endpoint ( cxlmd , dport ) ;
2022-05-18 16:34:31 -07:00
unlock :
2022-04-21 08:33:23 -07:00
device_unlock ( & parent_port - > dev ) ;
2022-02-04 07:18:31 -08:00
put_device ( & parent_port - > dev ) ;
2022-05-18 16:34:31 -07:00
if ( rc )
return rc ;
2022-04-22 15:58:11 -07:00
/*
* The kernel may be operating out of CXL memory on this device ,
* there is no spec defined way to determine whether this device
* preserves contents over suspend , and there is no simple way
* to arrange for the suspend image to avoid CXL memory which
* would setup a circular dependency between PCI resume and save
* state restoration .
*
* TODO : support suspend when all the regions this device is
* hosting are locked and covered by the system address map ,
* i . e . platform firmware owns restoring the HDM configuration
* that it locked .
*/
cxl_mem_active_inc ( ) ;
return devm_add_action_or_reset ( dev , enable_suspend , NULL ) ;
2022-02-04 07:18:31 -08:00
}
static struct cxl_driver cxl_mem_driver = {
. name = " cxl_mem " ,
. probe = cxl_mem_probe ,
. id = CXL_DEVICE_MEMORY_EXPANDER ,
} ;
module_cxl_driver ( cxl_mem_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_IMPORT_NS ( CXL ) ;
MODULE_ALIAS_CXL ( CXL_DEVICE_MEMORY_EXPANDER ) ;
/*
* create_endpoint ( ) wants to validate port driver attach immediately after
* endpoint registration .
*/
MODULE_SOFTDEP ( " pre: cxl_port " ) ;