Commit 362f533a authored by Linus Torvalds's avatar Linus Torvalds

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

Pull CXL (Compute Express Link) updates from Dan Williams:
 "The highlight is initial support for CXL memory hotplug. The static
  NUMA node (ACPI SRAT Physical Address to Proximity Domain) information
  known to platform firmware is extended to support the potential
  performance-class / memory-target nodes dynamically created from
  available CXL memory device capacity.

  New unit test infrastructure is added for validating health
  information payloads.

  Fixes to module reload stress and stack usage from exposure in -next
  are included. A symbol rename and some other miscellaneous fixups are
  included as well.

  Summary:

   - Rework ACPI sub-table infrastructure to optionally be used outside
     of __init scenarios and use it for CEDT.CFMWS sub-table parsing.

   - Add support for extending num_possible_nodes by the potential
     hotplug CXL memory ranges

   - Extend tools/testing/cxl with mock memory device health information

   - Fix a module-reload workqueue race

   - Fix excessive stack-frame usage

   - Rename the driver context data structure from "cxl_mem" since that
     name collides with a proposed driver name

   - Use EXPORT_SYMBOL_NS_GPL instead of -DDEFAULT_SYMBOL_NAMESPACE at
     build time"

* tag 'cxl-for-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl:
  cxl/core: Remove cxld_const_init in cxl_decoder_alloc()
  cxl/pmem: Fix module reload vs workqueue state
  ACPI: NUMA: Add a node and memblk for each CFMWS not in SRAT
  cxl/test: Mock acpi_table_parse_cedt()
  cxl/acpi: Convert CFMWS parsing to ACPI sub-table helpers
  ACPI: Add a context argument for table parsing handlers
  ACPI: Teach ACPI table parsing about the CEDT header format
  ACPI: Keep sub-table parsing infrastructure available for modules
  tools/testing/cxl: add mock output for the GET_HEALTH_INFO command
  cxl/memdev: Remove unused cxlmd field
  cxl/core: Convert to EXPORT_SYMBOL_NS_GPL
  cxl/memdev: Change cxl_mem to a more descriptive name
  cxl/mbox: Remove bad comment
  cxl/pmem: Fix reference counting for delayed work
parents 3acbdbf4 be185c29
...@@ -59,6 +59,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT ...@@ -59,6 +59,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT
config ACPI_CCA_REQUIRED config ACPI_CCA_REQUIRED
bool bool
config ACPI_TABLE_LIB
bool
config ACPI_DEBUGGER config ACPI_DEBUGGER
bool "AML debugger interface" bool "AML debugger interface"
select ACPI_DEBUG select ACPI_DEBUG
......
...@@ -297,6 +297,47 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) ...@@ -297,6 +297,47 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
out_err: out_err:
return -EINVAL; return -EINVAL;
} }
static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
void *arg, const unsigned long table_end)
{
struct acpi_cedt_cfmws *cfmws;
int *fake_pxm = arg;
u64 start, end;
int node;
cfmws = (struct acpi_cedt_cfmws *)header;
start = cfmws->base_hpa;
end = cfmws->base_hpa + cfmws->window_size;
/* Skip if the SRAT already described the NUMA details for this HPA */
node = phys_to_target_node(start);
if (node != NUMA_NO_NODE)
return 0;
node = acpi_map_pxm_to_node(*fake_pxm);
if (node == NUMA_NO_NODE) {
pr_err("ACPI NUMA: Too many proximity domains while processing CFMWS.\n");
return -EINVAL;
}
if (numa_add_memblk(node, start, end) < 0) {
/* CXL driver must handle the NUMA_NO_NODE case */
pr_warn("ACPI NUMA: Failed to add memblk for CFMWS node %d [mem %#llx-%#llx]\n",
node, start, end);
}
/* Set the next available fake_pxm value */
(*fake_pxm)++;
return 0;
}
#else
static int __init acpi_parse_cfmws(union acpi_subtable_headers *header,
void *arg, const unsigned long table_end)
{
return 0;
}
#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */ #endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
static int __init acpi_parse_slit(struct acpi_table_header *table) static int __init acpi_parse_slit(struct acpi_table_header *table)
...@@ -441,7 +482,7 @@ acpi_table_parse_srat(enum acpi_srat_type id, ...@@ -441,7 +482,7 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void) int __init acpi_numa_init(void)
{ {
int cnt = 0; int i, fake_pxm, cnt = 0;
if (acpi_disabled) if (acpi_disabled)
return -EINVAL; return -EINVAL;
...@@ -477,6 +518,22 @@ int __init acpi_numa_init(void) ...@@ -477,6 +518,22 @@ int __init acpi_numa_init(void)
/* SLIT: System Locality Information Table */ /* SLIT: System Locality Information Table */
acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
/*
* CXL Fixed Memory Window Structures (CFMWS) must be parsed
* after the SRAT. Create NUMA Nodes for CXL memory ranges that
* are defined in the CFMWS and not already defined in the SRAT.
* Initialize a fake_pxm as the first available PXM to emulate.
*/
/* fake_pxm is the next unused PXM value after SRAT parsing */
for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) {
if (node_to_pxm_map[i] > fake_pxm)
fake_pxm = node_to_pxm_map[i];
}
fake_pxm++;
acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, acpi_parse_cfmws,
&fake_pxm);
if (cnt < 0) if (cnt < 0)
return cnt; return cnt;
else if (!parsed_numa_memblks) else if (!parsed_numa_memblks)
......
...@@ -35,12 +35,13 @@ static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" }; ...@@ -35,12 +35,13 @@ static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
static int acpi_apic_instance __initdata; static int acpi_apic_instance __initdata_or_acpilib;
enum acpi_subtable_type { enum acpi_subtable_type {
ACPI_SUBTABLE_COMMON, ACPI_SUBTABLE_COMMON,
ACPI_SUBTABLE_HMAT, ACPI_SUBTABLE_HMAT,
ACPI_SUBTABLE_PRMT, ACPI_SUBTABLE_PRMT,
ACPI_SUBTABLE_CEDT,
}; };
struct acpi_subtable_entry { struct acpi_subtable_entry {
...@@ -52,7 +53,7 @@ struct acpi_subtable_entry { ...@@ -52,7 +53,7 @@ struct acpi_subtable_entry {
* Disable table checksum verification for the early stage due to the size * Disable table checksum verification for the early stage due to the size
* limitation of the current x86 early mapping implementation. * limitation of the current x86 early mapping implementation.
*/ */
static bool acpi_verify_table_checksum __initdata = false; static bool acpi_verify_table_checksum __initdata_or_acpilib = false;
void acpi_table_print_madt_entry(struct acpi_subtable_header *header) void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{ {
...@@ -216,7 +217,7 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) ...@@ -216,7 +217,7 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
} }
} }
static unsigned long __init static unsigned long __init_or_acpilib
acpi_get_entry_type(struct acpi_subtable_entry *entry) acpi_get_entry_type(struct acpi_subtable_entry *entry)
{ {
switch (entry->type) { switch (entry->type) {
...@@ -226,11 +227,13 @@ acpi_get_entry_type(struct acpi_subtable_entry *entry) ...@@ -226,11 +227,13 @@ acpi_get_entry_type(struct acpi_subtable_entry *entry)
return entry->hdr->hmat.type; return entry->hdr->hmat.type;
case ACPI_SUBTABLE_PRMT: case ACPI_SUBTABLE_PRMT:
return 0; return 0;
case ACPI_SUBTABLE_CEDT:
return entry->hdr->cedt.type;
} }
return 0; return 0;
} }
static unsigned long __init static unsigned long __init_or_acpilib
acpi_get_entry_length(struct acpi_subtable_entry *entry) acpi_get_entry_length(struct acpi_subtable_entry *entry)
{ {
switch (entry->type) { switch (entry->type) {
...@@ -240,11 +243,13 @@ acpi_get_entry_length(struct acpi_subtable_entry *entry) ...@@ -240,11 +243,13 @@ acpi_get_entry_length(struct acpi_subtable_entry *entry)
return entry->hdr->hmat.length; return entry->hdr->hmat.length;
case ACPI_SUBTABLE_PRMT: case ACPI_SUBTABLE_PRMT:
return entry->hdr->prmt.length; return entry->hdr->prmt.length;
case ACPI_SUBTABLE_CEDT:
return entry->hdr->cedt.length;
} }
return 0; return 0;
} }
static unsigned long __init static unsigned long __init_or_acpilib
acpi_get_subtable_header_length(struct acpi_subtable_entry *entry) acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
{ {
switch (entry->type) { switch (entry->type) {
...@@ -254,20 +259,40 @@ acpi_get_subtable_header_length(struct acpi_subtable_entry *entry) ...@@ -254,20 +259,40 @@ acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
return sizeof(entry->hdr->hmat); return sizeof(entry->hdr->hmat);
case ACPI_SUBTABLE_PRMT: case ACPI_SUBTABLE_PRMT:
return sizeof(entry->hdr->prmt); return sizeof(entry->hdr->prmt);
case ACPI_SUBTABLE_CEDT:
return sizeof(entry->hdr->cedt);
} }
return 0; return 0;
} }
static enum acpi_subtable_type __init static enum acpi_subtable_type __init_or_acpilib
acpi_get_subtable_type(char *id) acpi_get_subtable_type(char *id)
{ {
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0) if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
return ACPI_SUBTABLE_HMAT; return ACPI_SUBTABLE_HMAT;
if (strncmp(id, ACPI_SIG_PRMT, 4) == 0) if (strncmp(id, ACPI_SIG_PRMT, 4) == 0)
return ACPI_SUBTABLE_PRMT; return ACPI_SUBTABLE_PRMT;
if (strncmp(id, ACPI_SIG_CEDT, 4) == 0)
return ACPI_SUBTABLE_CEDT;
return ACPI_SUBTABLE_COMMON; return ACPI_SUBTABLE_COMMON;
} }
static __init_or_acpilib bool has_handler(struct acpi_subtable_proc *proc)
{
return proc->handler || proc->handler_arg;
}
static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
union acpi_subtable_headers *hdr,
unsigned long end)
{
if (proc->handler)
return proc->handler(hdr, end);
if (proc->handler_arg)
return proc->handler_arg(hdr, proc->arg, end);
return -EINVAL;
}
/** /**
* acpi_parse_entries_array - for each proc_num find a suitable subtable * acpi_parse_entries_array - for each proc_num find a suitable subtable
* *
...@@ -291,10 +316,10 @@ acpi_get_subtable_type(char *id) ...@@ -291,10 +316,10 @@ acpi_get_subtable_type(char *id)
* On success returns sum of all matching entries for all proc handlers. * On success returns sum of all matching entries for all proc handlers.
* Otherwise, -ENODEV or -EINVAL is returned. * Otherwise, -ENODEV or -EINVAL is returned.
*/ */
static int __init acpi_parse_entries_array(char *id, unsigned long table_size, static int __init_or_acpilib acpi_parse_entries_array(
struct acpi_table_header *table_header, char *id, unsigned long table_size,
struct acpi_subtable_proc *proc, int proc_num, struct acpi_table_header *table_header, struct acpi_subtable_proc *proc,
unsigned int max_entries) int proc_num, unsigned int max_entries)
{ {
struct acpi_subtable_entry entry; struct acpi_subtable_entry entry;
unsigned long table_end, subtable_len, entry_len; unsigned long table_end, subtable_len, entry_len;
...@@ -318,8 +343,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size, ...@@ -318,8 +343,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
for (i = 0; i < proc_num; i++) { for (i = 0; i < proc_num; i++) {
if (acpi_get_entry_type(&entry) != proc[i].id) if (acpi_get_entry_type(&entry) != proc[i].id)
continue; continue;
if (!proc[i].handler || if (!has_handler(&proc[i]) ||
(!errs && proc[i].handler(entry.hdr, table_end))) { (!errs &&
call_handler(&proc[i], entry.hdr, table_end))) {
errs++; errs++;
continue; continue;
} }
...@@ -352,10 +378,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size, ...@@ -352,10 +378,9 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
return errs ? -EINVAL : count; return errs ? -EINVAL : count;
} }
int __init acpi_table_parse_entries_array(char *id, int __init_or_acpilib acpi_table_parse_entries_array(
unsigned long table_size, char *id, unsigned long table_size, struct acpi_subtable_proc *proc,
struct acpi_subtable_proc *proc, int proc_num, int proc_num, unsigned int max_entries)
unsigned int max_entries)
{ {
struct acpi_table_header *table_header = NULL; struct acpi_table_header *table_header = NULL;
int count; int count;
...@@ -386,21 +411,41 @@ int __init acpi_table_parse_entries_array(char *id, ...@@ -386,21 +411,41 @@ int __init acpi_table_parse_entries_array(char *id,
return count; return count;
} }
int __init acpi_table_parse_entries(char *id, static int __init_or_acpilib __acpi_table_parse_entries(
unsigned long table_size, char *id, unsigned long table_size, int entry_id,
int entry_id, acpi_tbl_entry_handler handler, acpi_tbl_entry_handler_arg handler_arg,
acpi_tbl_entry_handler handler, void *arg, unsigned int max_entries)
unsigned int max_entries)
{ {
struct acpi_subtable_proc proc = { struct acpi_subtable_proc proc = {
.id = entry_id, .id = entry_id,
.handler = handler, .handler = handler,
.handler_arg = handler_arg,
.arg = arg,
}; };
return acpi_table_parse_entries_array(id, table_size, &proc, 1, return acpi_table_parse_entries_array(id, table_size, &proc, 1,
max_entries); max_entries);
} }
int __init_or_acpilib
acpi_table_parse_cedt(enum acpi_cedt_type id,
acpi_tbl_entry_handler_arg handler_arg, void *arg)
{
return __acpi_table_parse_entries(ACPI_SIG_CEDT,
sizeof(struct acpi_table_cedt), id,
NULL, handler_arg, arg, 0);
}
EXPORT_SYMBOL_ACPI_LIB(acpi_table_parse_cedt);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
unsigned int max_entries)
{
return __acpi_table_parse_entries(id, table_size, entry_id, handler,
NULL, NULL, max_entries);
}
int __init acpi_table_parse_madt(enum acpi_madt_type id, int __init acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler, unsigned int max_entries) acpi_tbl_entry_handler handler, unsigned int max_entries)
{ {
......
...@@ -51,6 +51,7 @@ config CXL_ACPI ...@@ -51,6 +51,7 @@ config CXL_ACPI
tristate "CXL ACPI: Platform Support" tristate "CXL ACPI: Platform Support"
depends on ACPI depends on ACPI
default CXL_BUS default CXL_BUS
select ACPI_TABLE_LIB
help help
Enable support for host managed device memory (HDM) resources Enable support for host managed device memory (HDM) resources
published by a platform's ACPI CXL memory layout description. See published by a platform's ACPI CXL memory layout description. See
......
...@@ -8,8 +8,6 @@ ...@@ -8,8 +8,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include "cxl.h" #include "cxl.h"
static struct acpi_table_header *acpi_cedt;
/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */ /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
#define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways) #define CFMWS_INTERLEAVE_WAYS(x) (1 << (x)->interleave_ways)
#define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8) #define CFMWS_INTERLEAVE_GRANULARITY(x) ((x)->granularity + 8)
...@@ -74,64 +72,47 @@ static int cxl_acpi_cfmws_verify(struct device *dev, ...@@ -74,64 +72,47 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
return 0; return 0;
} }
static void cxl_add_cfmws_decoders(struct device *dev, struct cxl_cfmws_context {
struct cxl_port *root_port) struct device *dev;
struct cxl_port *root_port;
};
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
const unsigned long end)
{ {
int target_map[CXL_DECODER_MAX_INTERLEAVE]; int target_map[CXL_DECODER_MAX_INTERLEAVE];
struct cxl_cfmws_context *ctx = arg;
struct cxl_port *root_port = ctx->root_port;
struct device *dev = ctx->dev;
struct acpi_cedt_cfmws *cfmws; struct acpi_cedt_cfmws *cfmws;
struct cxl_decoder *cxld; struct cxl_decoder *cxld;
acpi_size len, cur = 0; int rc, i;
void *cedt_subtable;
int rc;
len = acpi_cedt->length - sizeof(*acpi_cedt);
cedt_subtable = acpi_cedt + 1;
while (cur < len) {
struct acpi_cedt_header *c = cedt_subtable + cur;
int i;
if (c->type != ACPI_CEDT_TYPE_CFMWS) {
cur += c->length;
continue;
}
cfmws = cedt_subtable + cur; cfmws = (struct acpi_cedt_cfmws *) header;
if (cfmws->header.length < sizeof(*cfmws)) {
dev_warn_once(dev,
"CFMWS entry skipped:invalid length:%u\n",
cfmws->header.length);
cur += c->length;
continue;
}
rc = cxl_acpi_cfmws_verify(dev, cfmws); rc = cxl_acpi_cfmws_verify(dev, cfmws);
if (rc) { if (rc) {
dev_err(dev, "CFMWS range %#llx-%#llx not registered\n", dev_err(dev, "CFMWS range %#llx-%#llx not registered\n",
cfmws->base_hpa, cfmws->base_hpa + cfmws->base_hpa,
cfmws->window_size - 1); cfmws->base_hpa + cfmws->window_size - 1);
cur += c->length; return 0;
continue;
} }
for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++) for (i = 0; i < CFMWS_INTERLEAVE_WAYS(cfmws); i++)
target_map[i] = cfmws->interleave_targets[i]; target_map[i] = cfmws->interleave_targets[i];
cxld = cxl_decoder_alloc(root_port, cxld = cxl_decoder_alloc(root_port, CFMWS_INTERLEAVE_WAYS(cfmws));
CFMWS_INTERLEAVE_WAYS(cfmws));
if (IS_ERR(cxld)) if (IS_ERR(cxld))
goto next; return 0;
cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions); cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
cxld->target_type = CXL_DECODER_EXPANDER; cxld->target_type = CXL_DECODER_EXPANDER;
cxld->range = (struct range) { cxld->range = (struct range){
.start = cfmws->base_hpa, .start = cfmws->base_hpa,
.end = cfmws->base_hpa + cfmws->window_size - 1, .end = cfmws->base_hpa + cfmws->window_size - 1,
}; };
cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws); cxld->interleave_ways = CFMWS_INTERLEAVE_WAYS(cfmws);
cxld->interleave_granularity = cxld->interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY(cfmws);
CFMWS_INTERLEAVE_GRANULARITY(cfmws);
rc = cxl_decoder_add(cxld, target_map); rc = cxl_decoder_add(cxld, target_map);
if (rc) if (rc)
...@@ -140,68 +121,15 @@ static void cxl_add_cfmws_decoders(struct device *dev, ...@@ -140,68 +121,15 @@ static void cxl_add_cfmws_decoders(struct device *dev,
rc = cxl_decoder_autoremove(dev, cxld); rc = cxl_decoder_autoremove(dev, cxld);
if (rc) { if (rc) {
dev_err(dev, "Failed to add decoder for %#llx-%#llx\n", dev_err(dev, "Failed to add decoder for %#llx-%#llx\n",
cfmws->base_hpa, cfmws->base_hpa + cfmws->base_hpa,
cfmws->window_size - 1);
goto next;
}
dev_dbg(dev, "add: %s range %#llx-%#llx\n",
dev_name(&cxld->dev), cfmws->base_hpa,
cfmws->base_hpa + cfmws->window_size - 1); cfmws->base_hpa + cfmws->window_size - 1);
next: return 0;
cur += c->length;
}
}
static struct acpi_cedt_chbs *cxl_acpi_match_chbs(struct device *dev, u32 uid)
{
struct acpi_cedt_chbs *chbs, *chbs_match = NULL;
acpi_size len, cur = 0;
void *cedt_subtable;
len = acpi_cedt->length - sizeof(*acpi_cedt);
cedt_subtable = acpi_cedt + 1;
while (cur < len) {
struct acpi_cedt_header *c = cedt_subtable + cur;
if (c->type != ACPI_CEDT_TYPE_CHBS) {
cur += c->length;
continue;
}
chbs = cedt_subtable + cur;
if (chbs->header.length < sizeof(*chbs)) {
dev_warn_once(dev,
"CHBS entry skipped: invalid length:%u\n",
chbs->header.length);
cur += c->length;
continue;
}
if (chbs->uid != uid) {
cur += c->length;
continue;
}
if (chbs_match) {
dev_warn_once(dev,
"CHBS entry skipped: duplicate UID:%u\n",
uid);
cur += c->length;
continue;
}
chbs_match = chbs;
cur += c->length;
} }
dev_dbg(dev, "add: %s node: %d range %#llx-%#llx\n",
dev_name(&cxld->dev), phys_to_target_node(cxld->range.start),
cfmws->base_hpa, cfmws->base_hpa + cfmws->window_size - 1);
return chbs_match ? chbs_match : ERR_PTR(-ENODEV); return 0;
}
static resource_size_t get_chbcr(struct acpi_cedt_chbs *chbs)
{
return IS_ERR(chbs) ? CXL_RESOURCE_NONE : chbs->base;
} }
__mock int match_add_root_ports(struct pci_dev *pdev, void *data) __mock int match_add_root_ports(struct pci_dev *pdev, void *data)
...@@ -355,12 +283,36 @@ static int add_host_bridge_uport(struct device *match, void *arg) ...@@ -355,12 +283,36 @@ static int add_host_bridge_uport(struct device *match, void *arg)
return rc; return rc;
} }
struct cxl_chbs_context {
struct device *dev;
unsigned long long uid;
resource_size_t chbcr;
};
static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg,
const unsigned long end)
{
struct cxl_chbs_context *ctx = arg;
struct acpi_cedt_chbs *chbs;
if (ctx->chbcr)
return 0;
chbs = (struct acpi_cedt_chbs *) header;
if (ctx->uid != chbs->uid)
return 0;
ctx->chbcr = chbs->base;
return 0;
}
static int add_host_bridge_dport(struct device *match, void *arg) static int add_host_bridge_dport(struct device *match, void *arg)
{ {
int rc; int rc;
acpi_status status; acpi_status status;
unsigned long long uid; unsigned long long uid;
struct acpi_cedt_chbs *chbs; struct cxl_chbs_context ctx;
struct cxl_port *root_port = arg; struct cxl_port *root_port = arg;
struct device *host = root_port->dev.parent; struct device *host = root_port->dev.parent;
struct acpi_device *bridge = to_cxl_host_bridge(host, match); struct acpi_device *bridge = to_cxl_host_bridge(host, match);
...@@ -376,14 +328,19 @@ static int add_host_bridge_dport(struct device *match, void *arg) ...@@ -376,14 +328,19 @@ static int add_host_bridge_dport(struct device *match, void *arg)
return -ENODEV; return -ENODEV;
} }
chbs = cxl_acpi_match_chbs(host, uid); ctx = (struct cxl_chbs_context) {
if (IS_ERR(chbs)) { .dev = host,
.uid = uid,
};
acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx);
if (ctx.chbcr == 0) {
dev_warn(host, "No CHBS found for Host Bridge: %s\n", dev_warn(host, "No CHBS found for Host Bridge: %s\n",
dev_name(match)); dev_name(match));
return 0; return 0;
} }
rc = cxl_add_dport(root_port, match, uid, get_chbcr(chbs)); rc = cxl_add_dport(root_port, match, uid, ctx.chbcr);
if (rc) { if (rc) {
dev_err(host, "failed to add downstream port: %s\n", dev_err(host, "failed to add downstream port: %s\n",
dev_name(match)); dev_name(match));
...@@ -417,40 +374,29 @@ static int add_root_nvdimm_bridge(struct device *match, void *data) ...@@ -417,40 +374,29 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
return 1; return 1;
} }
static u32 cedt_instance(struct platform_device *pdev)
{
const bool *native_acpi0017 = acpi_device_get_match_data(&pdev->dev);
if (native_acpi0017 && *native_acpi0017)
return 0;
/* for cxl_test request a non-canonical instance */
return U32_MAX;
}
static int cxl_acpi_probe(struct platform_device *pdev) static int cxl_acpi_probe(struct platform_device *pdev)
{ {
int rc; int rc;
acpi_status status;
struct cxl_port *root_port; struct cxl_port *root_port;
struct device *host = &pdev->dev; struct device *host = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(host); struct acpi_device *adev = ACPI_COMPANION(host);
struct cxl_cfmws_context ctx;
root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
if (IS_ERR(root_port)) if (IS_ERR(root_port))
return PTR_ERR(root_port); return PTR_ERR(root_port);
dev_dbg(host, "add: %s\n", dev_name(&root_port->dev)); dev_dbg(host, "add: %s\n", dev_name(&root_port->dev));
status = acpi_get_table(ACPI_SIG_CEDT, cedt_instance(pdev), &acpi_cedt);
if (ACPI_FAILURE(status))
return -ENXIO;
rc = bus_for_each_dev(adev->dev.bus, NULL, root_port, rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
add_host_bridge_dport); add_host_bridge_dport);
if (rc) if (rc < 0)
goto out; return rc;
cxl_add_cfmws_decoders(host, root_port); ctx = (struct cxl_cfmws_context) {
.dev = host,
.root_port = root_port,
};
acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
/* /*
* Root level scanned with host-bridge as dports, now scan host-bridges * Root level scanned with host-bridge as dports, now scan host-bridges
...@@ -458,24 +404,20 @@ static int cxl_acpi_probe(struct platform_device *pdev) ...@@ -458,24 +404,20 @@ static int cxl_acpi_probe(struct platform_device *pdev)
*/ */
rc = bus_for_each_dev(adev->dev.bus, NULL, root_port, rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
add_host_bridge_uport); add_host_bridge_uport);
if (rc) if (rc < 0)
goto out; return rc;
if (IS_ENABLED(CONFIG_CXL_PMEM)) if (IS_ENABLED(CONFIG_CXL_PMEM))
rc = device_for_each_child(&root_port->dev, root_port, rc = device_for_each_child(&root_port->dev, root_port,
add_root_nvdimm_bridge); add_root_nvdimm_bridge);
out:
acpi_put_table(acpi_cedt);
if (rc < 0) if (rc < 0)
return rc; return rc;
return 0; return 0;
} }
static bool native_acpi0017 = true;
static const struct acpi_device_id cxl_acpi_ids[] = { static const struct acpi_device_id cxl_acpi_ids[] = {
{ "ACPI0017", (unsigned long) &native_acpi0017 }, { "ACPI0017" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids); MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
...@@ -491,3 +433,4 @@ static struct platform_driver cxl_acpi_driver = { ...@@ -491,3 +433,4 @@ static struct platform_driver cxl_acpi_driver = {
module_platform_driver(cxl_acpi_driver); module_platform_driver(cxl_acpi_driver);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(CXL); MODULE_IMPORT_NS(CXL);
MODULE_IMPORT_NS(ACPI);
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CXL_BUS) += cxl_core.o obj-$(CONFIG_CXL_BUS) += cxl_core.o
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=CXL -I$(srctree)/drivers/cxl ccflags-y += -I$(srctree)/drivers/cxl
cxl_core-y := bus.o cxl_core-y := bus.o
cxl_core-y += pmem.o cxl_core-y += pmem.o
cxl_core-y += regs.o cxl_core-y += regs.o
......
...@@ -200,7 +200,7 @@ bool is_root_decoder(struct device *dev) ...@@ -200,7 +200,7 @@ bool is_root_decoder(struct device *dev)
{ {
return dev->type == &cxl_decoder_root_type; return dev->type == &cxl_decoder_root_type;
} }
EXPORT_SYMBOL_GPL(is_root_decoder); EXPORT_SYMBOL_NS_GPL(is_root_decoder, CXL);
struct cxl_decoder *to_cxl_decoder(struct device *dev) struct cxl_decoder *to_cxl_decoder(struct device *dev)
{ {
...@@ -209,7 +209,7 @@ struct cxl_decoder *to_cxl_decoder(struct device *dev) ...@@ -209,7 +209,7 @@ struct cxl_decoder *to_cxl_decoder(struct device *dev)
return NULL; return NULL;
return container_of(dev, struct cxl_decoder, dev); return container_of(dev, struct cxl_decoder, dev);
} }
EXPORT_SYMBOL_GPL(to_cxl_decoder); EXPORT_SYMBOL_NS_GPL(to_cxl_decoder, CXL);
static void cxl_dport_release(struct cxl_dport *dport) static void cxl_dport_release(struct cxl_dport *dport)
{ {
...@@ -376,7 +376,7 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, ...@@ -376,7 +376,7 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport,
put_device(dev); put_device(dev);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
EXPORT_SYMBOL_GPL(devm_cxl_add_port); EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL);
static struct cxl_dport *find_dport(struct cxl_port *port, int id) static struct cxl_dport *find_dport(struct cxl_port *port, int id)
{ {
...@@ -451,7 +451,7 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id, ...@@ -451,7 +451,7 @@ int cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id,
cxl_dport_release(dport); cxl_dport_release(dport);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(cxl_add_dport); EXPORT_SYMBOL_NS_GPL(cxl_add_dport, CXL);
static int decoder_populate_targets(struct cxl_decoder *cxld, static int decoder_populate_targets(struct cxl_decoder *cxld,
struct cxl_port *port, int *target_map) struct cxl_port *port, int *target_map)
...@@ -485,9 +485,7 @@ static int decoder_populate_targets(struct cxl_decoder *cxld, ...@@ -485,9 +485,7 @@ static int decoder_populate_targets(struct cxl_decoder *cxld,
struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets)
{ {
struct cxl_decoder *cxld, cxld_const_init = { struct cxl_decoder *cxld;
.nr_targets = nr_targets,
};
struct device *dev; struct device *dev;
int rc = 0; int rc = 0;
...@@ -497,13 +495,13 @@ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) ...@@ -497,13 +495,13 @@ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets)
cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL); cxld = kzalloc(struct_size(cxld, target, nr_targets), GFP_KERNEL);
if (!cxld) if (!cxld)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memcpy(cxld, &cxld_const_init, sizeof(cxld_const_init));
rc = ida_alloc(&port->decoder_ida, GFP_KERNEL); rc = ida_alloc(&port->decoder_ida, GFP_KERNEL);
if (rc < 0) if (rc < 0)
goto err; goto err;
cxld->id = rc; cxld->id = rc;
cxld->nr_targets = nr_targets;
dev = &cxld->dev; dev = &cxld->dev;
device_initialize(dev); device_initialize(dev);
device_set_pm_not_required(dev); device_set_pm_not_required(dev);
...@@ -521,7 +519,7 @@ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets) ...@@ -521,7 +519,7 @@ struct cxl_decoder *cxl_decoder_alloc(struct cxl_port *port, int nr_targets)
kfree(cxld); kfree(cxld);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
EXPORT_SYMBOL_GPL(cxl_decoder_alloc); EXPORT_SYMBOL_NS_GPL(cxl_decoder_alloc, CXL);
int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
{ {
...@@ -550,7 +548,7 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map) ...@@ -550,7 +548,7 @@ int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map)
return device_add(dev); return device_add(dev);
} }
EXPORT_SYMBOL_GPL(cxl_decoder_add); EXPORT_SYMBOL_NS_GPL(cxl_decoder_add, CXL);
static void cxld_unregister(void *dev) static void cxld_unregister(void *dev)
{ {
...@@ -561,7 +559,7 @@ int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld) ...@@ -561,7 +559,7 @@ int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld)
{ {
return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev); return devm_add_action_or_reset(host, cxld_unregister, &cxld->dev);
} }
EXPORT_SYMBOL_GPL(cxl_decoder_autoremove); EXPORT_SYMBOL_NS_GPL(cxl_decoder_autoremove, CXL);
/** /**
* __cxl_driver_register - register a driver for the cxl bus * __cxl_driver_register - register a driver for the cxl bus
...@@ -594,13 +592,13 @@ int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner, ...@@ -594,13 +592,13 @@ int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner,
return driver_register(&cxl_drv->drv); return driver_register(&cxl_drv->drv);
} }
EXPORT_SYMBOL_GPL(__cxl_driver_register); EXPORT_SYMBOL_NS_GPL(__cxl_driver_register, CXL);
void cxl_driver_unregister(struct cxl_driver *cxl_drv) void cxl_driver_unregister(struct cxl_driver *cxl_drv)
{ {
driver_unregister(&cxl_drv->drv); driver_unregister(&cxl_drv->drv);
} }
EXPORT_SYMBOL_GPL(cxl_driver_unregister); EXPORT_SYMBOL_NS_GPL(cxl_driver_unregister, CXL);
static int cxl_device_id(struct device *dev) static int cxl_device_id(struct device *dev)
{ {
...@@ -642,7 +640,7 @@ struct bus_type cxl_bus_type = { ...@@ -642,7 +640,7 @@ struct bus_type cxl_bus_type = {
.probe = cxl_bus_probe, .probe = cxl_bus_probe,
.remove = cxl_bus_remove, .remove = cxl_bus_remove,
}; };
EXPORT_SYMBOL_GPL(cxl_bus_type); EXPORT_SYMBOL_NS_GPL(cxl_bus_type, CXL);
static __init int cxl_core_init(void) static __init int cxl_core_init(void)
{ {
......
...@@ -128,8 +128,8 @@ static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) ...@@ -128,8 +128,8 @@ static struct cxl_mem_command *cxl_mem_find_command(u16 opcode)
} }
/** /**
* cxl_mem_mbox_send_cmd() - Send a mailbox command to a memory device. * cxl_mbox_send_cmd() - Send a mailbox command to a device.
* @cxlm: The CXL memory device to communicate with. * @cxlds: The device data for the operation
* @opcode: Opcode for the mailbox command. * @opcode: Opcode for the mailbox command.
* @in: The input payload for the mailbox command. * @in: The input payload for the mailbox command.
* @in_size: The length of the input payload * @in_size: The length of the input payload
...@@ -148,10 +148,8 @@ static struct cxl_mem_command *cxl_mem_find_command(u16 opcode) ...@@ -148,10 +148,8 @@ static struct cxl_mem_command *cxl_mem_find_command(u16 opcode)
* Mailbox commands may execute successfully yet the device itself reported an * Mailbox commands may execute successfully yet the device itself reported an
* error. While this distinction can be useful for commands from userspace, the * error. While this distinction can be useful for commands from userspace, the
* kernel will only be able to use results when both are successful. * kernel will only be able to use results when both are successful.
*
* See __cxl_mem_mbox_send_cmd()
*/ */
int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in,
size_t in_size, void *out, size_t out_size) size_t in_size, void *out, size_t out_size)
{ {
const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); const struct cxl_mem_command *cmd = cxl_mem_find_command(opcode);
...@@ -164,10 +162,10 @@ int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, ...@@ -164,10 +162,10 @@ int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in,
}; };
int rc; int rc;
if (out_size > cxlm->payload_size) if (out_size > cxlds->payload_size)
return -E2BIG; return -E2BIG;
rc = cxlm->mbox_send(cxlm, &mbox_cmd); rc = cxlds->mbox_send(cxlds, &mbox_cmd);
if (rc) if (rc)
return rc; return rc;
...@@ -184,7 +182,7 @@ int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, ...@@ -184,7 +182,7 @@ int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxl_mem_mbox_send_cmd); EXPORT_SYMBOL_NS_GPL(cxl_mbox_send_cmd, CXL);
static bool cxl_mem_raw_command_allowed(u16 opcode) static bool cxl_mem_raw_command_allowed(u16 opcode)
{ {
...@@ -211,7 +209,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode) ...@@ -211,7 +209,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
/** /**
* cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND. * cxl_validate_cmd_from_user() - Check fields for CXL_MEM_SEND_COMMAND.
* @cxlm: &struct cxl_mem device whose mailbox will be used. * @cxlds: The device data for the operation
* @send_cmd: &struct cxl_send_command copied in from userspace. * @send_cmd: &struct cxl_send_command copied in from userspace.
* @out_cmd: Sanitized and populated &struct cxl_mem_command. * @out_cmd: Sanitized and populated &struct cxl_mem_command.
* *
...@@ -228,7 +226,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode) ...@@ -228,7 +226,7 @@ static bool cxl_mem_raw_command_allowed(u16 opcode)
* *
* See handle_mailbox_cmd_from_user() * See handle_mailbox_cmd_from_user()
*/ */
static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, static int cxl_validate_cmd_from_user(struct cxl_dev_state *cxlds,
const struct cxl_send_command *send_cmd, const struct cxl_send_command *send_cmd,
struct cxl_mem_command *out_cmd) struct cxl_mem_command *out_cmd)
{ {
...@@ -243,7 +241,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, ...@@ -243,7 +241,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm,
* supports, but output can be arbitrarily large (simply write out as * supports, but output can be arbitrarily large (simply write out as
* much data as the hardware provides). * much data as the hardware provides).
*/ */
if (send_cmd->in.size > cxlm->payload_size) if (send_cmd->in.size > cxlds->payload_size)
return -EINVAL; return -EINVAL;
/* /*
...@@ -269,7 +267,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, ...@@ -269,7 +267,7 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm,
* gets passed along without further checking, so it must be * gets passed along without further checking, so it must be
* validated here. * validated here.
*/ */
if (send_cmd->out.size > cxlm->payload_size) if (send_cmd->out.size > cxlds->payload_size)
return -EINVAL; return -EINVAL;
if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode)) if (!cxl_mem_raw_command_allowed(send_cmd->raw.opcode))
...@@ -294,11 +292,11 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm, ...@@ -294,11 +292,11 @@ static int cxl_validate_cmd_from_user(struct cxl_mem *cxlm,
info = &c->info; info = &c->info;
/* Check that the command is enabled for hardware */ /* Check that the command is enabled for hardware */
if (!test_bit(info->id, cxlm->enabled_cmds)) if (!test_bit(info->id, cxlds->enabled_cmds))
return -ENOTTY; return -ENOTTY;
/* Check that the command is not claimed for exclusive kernel use */ /* Check that the command is not claimed for exclusive kernel use */
if (test_bit(info->id, cxlm->exclusive_cmds)) if (test_bit(info->id, cxlds->exclusive_cmds))
return -EBUSY; return -EBUSY;
/* Check the input buffer is the expected size */ /* Check the input buffer is the expected size */
...@@ -356,7 +354,7 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd, ...@@ -356,7 +354,7 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd,
/** /**
* handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace. * handle_mailbox_cmd_from_user() - Dispatch a mailbox command for userspace.
* @cxlm: The CXL memory device to communicate with. * @cxlds: The device data for the operation
* @cmd: The validated command. * @cmd: The validated command.
* @in_payload: Pointer to userspace's input payload. * @in_payload: Pointer to userspace's input payload.
* @out_payload: Pointer to userspace's output payload. * @out_payload: Pointer to userspace's output payload.
...@@ -379,12 +377,12 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd, ...@@ -379,12 +377,12 @@ int cxl_query_cmd(struct cxl_memdev *cxlmd,
* *
* See cxl_send_cmd(). * See cxl_send_cmd().
*/ */
static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, static int handle_mailbox_cmd_from_user(struct cxl_dev_state *cxlds,
const struct cxl_mem_command *cmd, const struct cxl_mem_command *cmd,
u64 in_payload, u64 out_payload, u64 in_payload, u64 out_payload,
s32 *size_out, u32 *retval) s32 *size_out, u32 *retval)
{ {
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
struct cxl_mbox_cmd mbox_cmd = { struct cxl_mbox_cmd mbox_cmd = {
.opcode = cmd->opcode, .opcode = cmd->opcode,
.size_in = cmd->info.size_in, .size_in = cmd->info.size_in,
...@@ -417,7 +415,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, ...@@ -417,7 +415,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm,
dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW, dev_WARN_ONCE(dev, cmd->info.id == CXL_MEM_COMMAND_ID_RAW,
"raw command path used\n"); "raw command path used\n");
rc = cxlm->mbox_send(cxlm, &mbox_cmd); rc = cxlds->mbox_send(cxlds, &mbox_cmd);
if (rc) if (rc)
goto out; goto out;
...@@ -447,7 +445,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm, ...@@ -447,7 +445,7 @@ static int handle_mailbox_cmd_from_user(struct cxl_mem *cxlm,
int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
{ {
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
struct device *dev = &cxlmd->dev; struct device *dev = &cxlmd->dev;
struct cxl_send_command send; struct cxl_send_command send;
struct cxl_mem_command c; struct cxl_mem_command c;
...@@ -458,15 +456,15 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) ...@@ -458,15 +456,15 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
if (copy_from_user(&send, s, sizeof(send))) if (copy_from_user(&send, s, sizeof(send)))
return -EFAULT; return -EFAULT;
rc = cxl_validate_cmd_from_user(cxlmd->cxlm, &send, &c); rc = cxl_validate_cmd_from_user(cxlmd->cxlds, &send, &c);
if (rc) if (rc)
return rc; return rc;
/* Prepare to handle a full payload for variable sized output */ /* Prepare to handle a full payload for variable sized output */
if (c.info.size_out < 0) if (c.info.size_out < 0)
c.info.size_out = cxlm->payload_size; c.info.size_out = cxlds->payload_size;
rc = handle_mailbox_cmd_from_user(cxlm, &c, send.in.payload, rc = handle_mailbox_cmd_from_user(cxlds, &c, send.in.payload,
send.out.payload, &send.out.size, send.out.payload, &send.out.size,
&send.retval); &send.retval);
if (rc) if (rc)
...@@ -478,13 +476,13 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s) ...@@ -478,13 +476,13 @@ int cxl_send_cmd(struct cxl_memdev *cxlmd, struct cxl_send_command __user *s)
return 0; return 0;
} }
static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) static int cxl_xfer_log(struct cxl_dev_state *cxlds, uuid_t *uuid, u32 size, u8 *out)
{ {
u32 remaining = size; u32 remaining = size;
u32 offset = 0; u32 offset = 0;
while (remaining) { while (remaining) {
u32 xfer_size = min_t(u32, remaining, cxlm->payload_size); u32 xfer_size = min_t(u32, remaining, cxlds->payload_size);
struct cxl_mbox_get_log log = { struct cxl_mbox_get_log log = {
.uuid = *uuid, .uuid = *uuid,
.offset = cpu_to_le32(offset), .offset = cpu_to_le32(offset),
...@@ -492,8 +490,8 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) ...@@ -492,8 +490,8 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out)
}; };
int rc; int rc;
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LOG, &log, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LOG, &log, sizeof(log),
sizeof(log), out, xfer_size); out, xfer_size);
if (rc < 0) if (rc < 0)
return rc; return rc;
...@@ -507,14 +505,14 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out) ...@@ -507,14 +505,14 @@ static int cxl_xfer_log(struct cxl_mem *cxlm, uuid_t *uuid, u32 size, u8 *out)
/** /**
* cxl_walk_cel() - Walk through the Command Effects Log. * cxl_walk_cel() - Walk through the Command Effects Log.
* @cxlm: Device. * @cxlds: The device data for the operation
* @size: Length of the Command Effects Log. * @size: Length of the Command Effects Log.
* @cel: CEL * @cel: CEL
* *
* Iterate over each entry in the CEL and determine if the driver supports the * Iterate over each entry in the CEL and determine if the driver supports the
* command. If so, the command is enabled for the device and can be used later. * command. If so, the command is enabled for the device and can be used later.
*/ */
static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) static void cxl_walk_cel(struct cxl_dev_state *cxlds, size_t size, u8 *cel)
{ {
struct cxl_cel_entry *cel_entry; struct cxl_cel_entry *cel_entry;
const int cel_entries = size / sizeof(*cel_entry); const int cel_entries = size / sizeof(*cel_entry);
...@@ -527,26 +525,26 @@ static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel) ...@@ -527,26 +525,26 @@ static void cxl_walk_cel(struct cxl_mem *cxlm, size_t size, u8 *cel)
struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); struct cxl_mem_command *cmd = cxl_mem_find_command(opcode);
if (!cmd) { if (!cmd) {
dev_dbg(cxlm->dev, dev_dbg(cxlds->dev,
"Opcode 0x%04x unsupported by driver", opcode); "Opcode 0x%04x unsupported by driver", opcode);
continue; continue;
} }
set_bit(cmd->info.id, cxlm->enabled_cmds); set_bit(cmd->info.id, cxlds->enabled_cmds);
} }
} }
static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_mem *cxlm) static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_dev_state *cxlds)
{ {
struct cxl_mbox_get_supported_logs *ret; struct cxl_mbox_get_supported_logs *ret;
int rc; int rc;
ret = kvmalloc(cxlm->payload_size, GFP_KERNEL); ret = kvmalloc(cxlds->payload_size, GFP_KERNEL);
if (!ret) if (!ret)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_SUPPORTED_LOGS, NULL, 0, ret,
0, ret, cxlm->payload_size); cxlds->payload_size);
if (rc < 0) { if (rc < 0) {
kvfree(ret); kvfree(ret);
return ERR_PTR(rc); return ERR_PTR(rc);
...@@ -567,23 +565,23 @@ static const uuid_t log_uuid[] = { ...@@ -567,23 +565,23 @@ static const uuid_t log_uuid[] = {
}; };
/** /**
* cxl_mem_enumerate_cmds() - Enumerate commands for a device. * cxl_enumerate_cmds() - Enumerate commands for a device.
* @cxlm: The device. * @cxlds: The device data for the operation
* *
* Returns 0 if enumerate completed successfully. * Returns 0 if enumerate completed successfully.
* *
* CXL devices have optional support for certain commands. This function will * CXL devices have optional support for certain commands. This function will
* determine the set of supported commands for the hardware and update the * determine the set of supported commands for the hardware and update the
* enabled_cmds bitmap in the @cxlm. * enabled_cmds bitmap in the @cxlds.
*/ */
int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) int cxl_enumerate_cmds(struct cxl_dev_state *cxlds)
{ {
struct cxl_mbox_get_supported_logs *gsl; struct cxl_mbox_get_supported_logs *gsl;
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
struct cxl_mem_command *cmd; struct cxl_mem_command *cmd;
int i, rc; int i, rc;
gsl = cxl_get_gsl(cxlm); gsl = cxl_get_gsl(cxlds);
if (IS_ERR(gsl)) if (IS_ERR(gsl))
return PTR_ERR(gsl); return PTR_ERR(gsl);
...@@ -604,19 +602,19 @@ int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) ...@@ -604,19 +602,19 @@ int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm)
goto out; goto out;
} }
rc = cxl_xfer_log(cxlm, &uuid, size, log); rc = cxl_xfer_log(cxlds, &uuid, size, log);
if (rc) { if (rc) {
kvfree(log); kvfree(log);
goto out; goto out;
} }
cxl_walk_cel(cxlm, size, log); cxl_walk_cel(cxlds, size, log);
kvfree(log); kvfree(log);
/* In case CEL was bogus, enable some default commands. */ /* In case CEL was bogus, enable some default commands. */
cxl_for_each_cmd(cmd) cxl_for_each_cmd(cmd)
if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE) if (cmd->flags & CXL_CMD_FLAG_FORCE_ENABLE)
set_bit(cmd->info.id, cxlm->enabled_cmds); set_bit(cmd->info.id, cxlds->enabled_cmds);
/* Found the required CEL */ /* Found the required CEL */
rc = 0; rc = 0;
...@@ -626,11 +624,11 @@ int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm) ...@@ -626,11 +624,11 @@ int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm)
kvfree(gsl); kvfree(gsl);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(cxl_mem_enumerate_cmds); EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
/** /**
* cxl_mem_get_partition_info - Get partition info * cxl_mem_get_partition_info - Get partition info
* @cxlm: cxl_mem instance to update partition info * @cxlds: The device data for the operation
* *
* Retrieve the current partition info for the device specified. The active * Retrieve the current partition info for the device specified. The active
* values are the current capacity in bytes. If not 0, the 'next' values are * values are the current capacity in bytes. If not 0, the 'next' values are
...@@ -640,7 +638,7 @@ EXPORT_SYMBOL_GPL(cxl_mem_enumerate_cmds); ...@@ -640,7 +638,7 @@ EXPORT_SYMBOL_GPL(cxl_mem_enumerate_cmds);
* *
* See CXL @8.2.9.5.2.1 Get Partition Info * See CXL @8.2.9.5.2.1 Get Partition Info
*/ */
static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) static int cxl_mem_get_partition_info(struct cxl_dev_state *cxlds)
{ {
struct cxl_mbox_get_partition_info { struct cxl_mbox_get_partition_info {
__le64 active_volatile_cap; __le64 active_volatile_cap;
...@@ -650,124 +648,124 @@ static int cxl_mem_get_partition_info(struct cxl_mem *cxlm) ...@@ -650,124 +648,124 @@ static int cxl_mem_get_partition_info(struct cxl_mem *cxlm)
} __packed pi; } __packed pi;
int rc; int rc;
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_PARTITION_INFO, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_PARTITION_INFO, NULL, 0,
NULL, 0, &pi, sizeof(pi)); &pi, sizeof(pi));
if (rc) if (rc)
return rc; return rc;
cxlm->active_volatile_bytes = cxlds->active_volatile_bytes =
le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(pi.active_volatile_cap) * CXL_CAPACITY_MULTIPLIER;
cxlm->active_persistent_bytes = cxlds->active_persistent_bytes =
le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(pi.active_persistent_cap) * CXL_CAPACITY_MULTIPLIER;
cxlm->next_volatile_bytes = cxlds->next_volatile_bytes =
le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER;
cxlm->next_persistent_bytes = cxlds->next_persistent_bytes =
le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(pi.next_volatile_cap) * CXL_CAPACITY_MULTIPLIER;
return 0; return 0;
} }
/** /**
* cxl_mem_identify() - Send the IDENTIFY command to the device. * cxl_dev_state_identify() - Send the IDENTIFY command to the device.
* @cxlm: The device to identify. * @cxlds: The device data for the operation
* *
* Return: 0 if identify was executed successfully. * Return: 0 if identify was executed successfully.
* *
* This will dispatch the identify command to the device and on success populate * This will dispatch the identify command to the device and on success populate
* structures to be exported to sysfs. * structures to be exported to sysfs.
*/ */
int cxl_mem_identify(struct cxl_mem *cxlm) int cxl_dev_state_identify(struct cxl_dev_state *cxlds)
{ {
/* See CXL 2.0 Table 175 Identify Memory Device Output Payload */ /* See CXL 2.0 Table 175 Identify Memory Device Output Payload */
struct cxl_mbox_identify id; struct cxl_mbox_identify id;
int rc; int rc;
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_IDENTIFY, NULL, 0, &id,
sizeof(id)); sizeof(id));
if (rc < 0) if (rc < 0)
return rc; return rc;
cxlm->total_bytes = cxlds->total_bytes =
le64_to_cpu(id.total_capacity) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(id.total_capacity) * CXL_CAPACITY_MULTIPLIER;
cxlm->volatile_only_bytes = cxlds->volatile_only_bytes =
le64_to_cpu(id.volatile_capacity) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(id.volatile_capacity) * CXL_CAPACITY_MULTIPLIER;
cxlm->persistent_only_bytes = cxlds->persistent_only_bytes =
le64_to_cpu(id.persistent_capacity) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(id.persistent_capacity) * CXL_CAPACITY_MULTIPLIER;
cxlm->partition_align_bytes = cxlds->partition_align_bytes =
le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER; le64_to_cpu(id.partition_align) * CXL_CAPACITY_MULTIPLIER;
dev_dbg(cxlm->dev, dev_dbg(cxlds->dev,
"Identify Memory Device\n" "Identify Memory Device\n"
" total_bytes = %#llx\n" " total_bytes = %#llx\n"
" volatile_only_bytes = %#llx\n" " volatile_only_bytes = %#llx\n"
" persistent_only_bytes = %#llx\n" " persistent_only_bytes = %#llx\n"
" partition_align_bytes = %#llx\n", " partition_align_bytes = %#llx\n",
cxlm->total_bytes, cxlm->volatile_only_bytes, cxlds->total_bytes, cxlds->volatile_only_bytes,
cxlm->persistent_only_bytes, cxlm->partition_align_bytes); cxlds->persistent_only_bytes, cxlds->partition_align_bytes);
cxlm->lsa_size = le32_to_cpu(id.lsa_size); cxlds->lsa_size = le32_to_cpu(id.lsa_size);
memcpy(cxlm->firmware_version, id.fw_revision, sizeof(id.fw_revision)); memcpy(cxlds->firmware_version, id.fw_revision, sizeof(id.fw_revision));
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxl_mem_identify); EXPORT_SYMBOL_NS_GPL(cxl_dev_state_identify, CXL);
int cxl_mem_create_range_info(struct cxl_mem *cxlm) int cxl_mem_create_range_info(struct cxl_dev_state *cxlds)
{ {
int rc; int rc;
if (cxlm->partition_align_bytes == 0) { if (cxlds->partition_align_bytes == 0) {
cxlm->ram_range.start = 0; cxlds->ram_range.start = 0;
cxlm->ram_range.end = cxlm->volatile_only_bytes - 1; cxlds->ram_range.end = cxlds->volatile_only_bytes - 1;
cxlm->pmem_range.start = cxlm->volatile_only_bytes; cxlds->pmem_range.start = cxlds->volatile_only_bytes;
cxlm->pmem_range.end = cxlm->volatile_only_bytes + cxlds->pmem_range.end = cxlds->volatile_only_bytes +
cxlm->persistent_only_bytes - 1; cxlds->persistent_only_bytes - 1;
return 0; return 0;
} }
rc = cxl_mem_get_partition_info(cxlm); rc = cxl_mem_get_partition_info(cxlds);
if (rc) { if (rc) {
dev_err(cxlm->dev, "Failed to query partition information\n"); dev_err(cxlds->dev, "Failed to query partition information\n");
return rc; return rc;
} }
dev_dbg(cxlm->dev, dev_dbg(cxlds->dev,
"Get Partition Info\n" "Get Partition Info\n"
" active_volatile_bytes = %#llx\n" " active_volatile_bytes = %#llx\n"
" active_persistent_bytes = %#llx\n" " active_persistent_bytes = %#llx\n"
" next_volatile_bytes = %#llx\n" " next_volatile_bytes = %#llx\n"
" next_persistent_bytes = %#llx\n", " next_persistent_bytes = %#llx\n",
cxlm->active_volatile_bytes, cxlm->active_persistent_bytes, cxlds->active_volatile_bytes, cxlds->active_persistent_bytes,
cxlm->next_volatile_bytes, cxlm->next_persistent_bytes); cxlds->next_volatile_bytes, cxlds->next_persistent_bytes);
cxlm->ram_range.start = 0; cxlds->ram_range.start = 0;
cxlm->ram_range.end = cxlm->active_volatile_bytes - 1; cxlds->ram_range.end = cxlds->active_volatile_bytes - 1;
cxlm->pmem_range.start = cxlm->active_volatile_bytes; cxlds->pmem_range.start = cxlds->active_volatile_bytes;
cxlm->pmem_range.end = cxlds->pmem_range.end =
cxlm->active_volatile_bytes + cxlm->active_persistent_bytes - 1; cxlds->active_volatile_bytes + cxlds->active_persistent_bytes - 1;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxl_mem_create_range_info); EXPORT_SYMBOL_NS_GPL(cxl_mem_create_range_info, CXL);
struct cxl_mem *cxl_mem_create(struct device *dev) struct cxl_dev_state *cxl_dev_state_create(struct device *dev)
{ {
struct cxl_mem *cxlm; struct cxl_dev_state *cxlds;
cxlm = devm_kzalloc(dev, sizeof(*cxlm), GFP_KERNEL); cxlds = devm_kzalloc(dev, sizeof(*cxlds), GFP_KERNEL);
if (!cxlm) { if (!cxlds) {
dev_err(dev, "No memory available\n"); dev_err(dev, "No memory available\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
mutex_init(&cxlm->mbox_mutex); mutex_init(&cxlds->mbox_mutex);
cxlm->dev = dev; cxlds->dev = dev;
return cxlm; return cxlds;
} }
EXPORT_SYMBOL_GPL(cxl_mem_create); EXPORT_SYMBOL_NS_GPL(cxl_dev_state_create, CXL);
static struct dentry *cxl_debugfs; static struct dentry *cxl_debugfs;
......
...@@ -37,9 +37,9 @@ static ssize_t firmware_version_show(struct device *dev, ...@@ -37,9 +37,9 @@ static ssize_t firmware_version_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
return sysfs_emit(buf, "%.16s\n", cxlm->firmware_version); return sysfs_emit(buf, "%.16s\n", cxlds->firmware_version);
} }
static DEVICE_ATTR_RO(firmware_version); static DEVICE_ATTR_RO(firmware_version);
...@@ -47,9 +47,9 @@ static ssize_t payload_max_show(struct device *dev, ...@@ -47,9 +47,9 @@ static ssize_t payload_max_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
return sysfs_emit(buf, "%zu\n", cxlm->payload_size); return sysfs_emit(buf, "%zu\n", cxlds->payload_size);
} }
static DEVICE_ATTR_RO(payload_max); static DEVICE_ATTR_RO(payload_max);
...@@ -57,9 +57,9 @@ static ssize_t label_storage_size_show(struct device *dev, ...@@ -57,9 +57,9 @@ static ssize_t label_storage_size_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
return sysfs_emit(buf, "%zu\n", cxlm->lsa_size); return sysfs_emit(buf, "%zu\n", cxlds->lsa_size);
} }
static DEVICE_ATTR_RO(label_storage_size); static DEVICE_ATTR_RO(label_storage_size);
...@@ -67,8 +67,8 @@ static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr, ...@@ -67,8 +67,8 @@ static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
unsigned long long len = range_len(&cxlm->ram_range); unsigned long long len = range_len(&cxlds->ram_range);
return sysfs_emit(buf, "%#llx\n", len); return sysfs_emit(buf, "%#llx\n", len);
} }
...@@ -80,8 +80,8 @@ static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr, ...@@ -80,8 +80,8 @@ static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
unsigned long long len = range_len(&cxlm->pmem_range); unsigned long long len = range_len(&cxlds->pmem_range);
return sysfs_emit(buf, "%#llx\n", len); return sysfs_emit(buf, "%#llx\n", len);
} }
...@@ -136,42 +136,42 @@ static const struct device_type cxl_memdev_type = { ...@@ -136,42 +136,42 @@ static const struct device_type cxl_memdev_type = {
/** /**
* set_exclusive_cxl_commands() - atomically disable user cxl commands * set_exclusive_cxl_commands() - atomically disable user cxl commands
* @cxlm: cxl_mem instance to modify * @cxlds: The device state to operate on
* @cmds: bitmap of commands to mark exclusive * @cmds: bitmap of commands to mark exclusive
* *
* Grab the cxl_memdev_rwsem in write mode to flush in-flight * Grab the cxl_memdev_rwsem in write mode to flush in-flight
* invocations of the ioctl path and then disable future execution of * invocations of the ioctl path and then disable future execution of
* commands with the command ids set in @cmds. * commands with the command ids set in @cmds.
*/ */
void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds)
{ {
down_write(&cxl_memdev_rwsem); down_write(&cxl_memdev_rwsem);
bitmap_or(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, bitmap_or(cxlds->exclusive_cmds, cxlds->exclusive_cmds, cmds,
CXL_MEM_COMMAND_ID_MAX); CXL_MEM_COMMAND_ID_MAX);
up_write(&cxl_memdev_rwsem); up_write(&cxl_memdev_rwsem);
} }
EXPORT_SYMBOL_GPL(set_exclusive_cxl_commands); EXPORT_SYMBOL_NS_GPL(set_exclusive_cxl_commands, CXL);
/** /**
* clear_exclusive_cxl_commands() - atomically enable user cxl commands * clear_exclusive_cxl_commands() - atomically enable user cxl commands
* @cxlm: cxl_mem instance to modify * @cxlds: The device state to modify
* @cmds: bitmap of commands to mark available for userspace * @cmds: bitmap of commands to mark available for userspace
*/ */
void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds) void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds)
{ {
down_write(&cxl_memdev_rwsem); down_write(&cxl_memdev_rwsem);
bitmap_andnot(cxlm->exclusive_cmds, cxlm->exclusive_cmds, cmds, bitmap_andnot(cxlds->exclusive_cmds, cxlds->exclusive_cmds, cmds,
CXL_MEM_COMMAND_ID_MAX); CXL_MEM_COMMAND_ID_MAX);
up_write(&cxl_memdev_rwsem); up_write(&cxl_memdev_rwsem);
} }
EXPORT_SYMBOL_GPL(clear_exclusive_cxl_commands); EXPORT_SYMBOL_NS_GPL(clear_exclusive_cxl_commands, CXL);
static void cxl_memdev_shutdown(struct device *dev) static void cxl_memdev_shutdown(struct device *dev)
{ {
struct cxl_memdev *cxlmd = to_cxl_memdev(dev); struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
down_write(&cxl_memdev_rwsem); down_write(&cxl_memdev_rwsem);
cxlmd->cxlm = NULL; cxlmd->cxlds = NULL;
up_write(&cxl_memdev_rwsem); up_write(&cxl_memdev_rwsem);
} }
...@@ -185,7 +185,7 @@ static void cxl_memdev_unregister(void *_cxlmd) ...@@ -185,7 +185,7 @@ static void cxl_memdev_unregister(void *_cxlmd)
put_device(dev); put_device(dev);
} }
static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, static struct cxl_memdev *cxl_memdev_alloc(struct cxl_dev_state *cxlds,
const struct file_operations *fops) const struct file_operations *fops)
{ {
struct cxl_memdev *cxlmd; struct cxl_memdev *cxlmd;
...@@ -204,7 +204,7 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm, ...@@ -204,7 +204,7 @@ static struct cxl_memdev *cxl_memdev_alloc(struct cxl_mem *cxlm,
dev = &cxlmd->dev; dev = &cxlmd->dev;
device_initialize(dev); device_initialize(dev);
dev->parent = cxlm->dev; dev->parent = cxlds->dev;
dev->bus = &cxl_bus_type; dev->bus = &cxl_bus_type;
dev->devt = MKDEV(cxl_mem_major, cxlmd->id); dev->devt = MKDEV(cxl_mem_major, cxlmd->id);
dev->type = &cxl_memdev_type; dev->type = &cxl_memdev_type;
...@@ -239,7 +239,7 @@ static long cxl_memdev_ioctl(struct file *file, unsigned int cmd, ...@@ -239,7 +239,7 @@ static long cxl_memdev_ioctl(struct file *file, unsigned int cmd,
int rc = -ENXIO; int rc = -ENXIO;
down_read(&cxl_memdev_rwsem); down_read(&cxl_memdev_rwsem);
if (cxlmd->cxlm) if (cxlmd->cxlds)
rc = __cxl_memdev_ioctl(cxlmd, cmd, arg); rc = __cxl_memdev_ioctl(cxlmd, cmd, arg);
up_read(&cxl_memdev_rwsem); up_read(&cxl_memdev_rwsem);
...@@ -276,15 +276,14 @@ static const struct file_operations cxl_memdev_fops = { ...@@ -276,15 +276,14 @@ static const struct file_operations cxl_memdev_fops = {
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
struct cxl_memdev * struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds)
devm_cxl_add_memdev(struct cxl_mem *cxlm)
{ {
struct cxl_memdev *cxlmd; struct cxl_memdev *cxlmd;
struct device *dev; struct device *dev;
struct cdev *cdev; struct cdev *cdev;
int rc; int rc;
cxlmd = cxl_memdev_alloc(cxlm, &cxl_memdev_fops); cxlmd = cxl_memdev_alloc(cxlds, &cxl_memdev_fops);
if (IS_ERR(cxlmd)) if (IS_ERR(cxlmd))
return cxlmd; return cxlmd;
...@@ -297,14 +296,14 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm) ...@@ -297,14 +296,14 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm)
* Activate ioctl operations, no cxl_memdev_rwsem manipulation * Activate ioctl operations, no cxl_memdev_rwsem manipulation
* needed as this is ordered with cdev_add() publishing the device. * needed as this is ordered with cdev_add() publishing the device.
*/ */
cxlmd->cxlm = cxlm; cxlmd->cxlds = cxlds;
cdev = &cxlmd->cdev; cdev = &cxlmd->cdev;
rc = cdev_device_add(cdev, dev); rc = cdev_device_add(cdev, dev);
if (rc) if (rc)
goto err; goto err;
rc = devm_add_action_or_reset(cxlm->dev, cxl_memdev_unregister, cxlmd); rc = devm_add_action_or_reset(cxlds->dev, cxl_memdev_unregister, cxlmd);
if (rc) if (rc)
return ERR_PTR(rc); return ERR_PTR(rc);
return cxlmd; return cxlmd;
...@@ -318,7 +317,7 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm) ...@@ -318,7 +317,7 @@ devm_cxl_add_memdev(struct cxl_mem *cxlm)
put_device(dev); put_device(dev);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
EXPORT_SYMBOL_GPL(devm_cxl_add_memdev); EXPORT_SYMBOL_NS_GPL(devm_cxl_add_memdev, CXL);
__init int cxl_memdev_init(void) __init int cxl_memdev_init(void)
{ {
......
...@@ -49,12 +49,18 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev) ...@@ -49,12 +49,18 @@ struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev)
return NULL; return NULL;
return container_of(dev, struct cxl_nvdimm_bridge, dev); return container_of(dev, struct cxl_nvdimm_bridge, dev);
} }
EXPORT_SYMBOL_GPL(to_cxl_nvdimm_bridge); EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm_bridge, CXL);
__mock int match_nvdimm_bridge(struct device *dev, const void *data) bool is_cxl_nvdimm_bridge(struct device *dev)
{ {
return dev->type == &cxl_nvdimm_bridge_type; return dev->type == &cxl_nvdimm_bridge_type;
} }
EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm_bridge, CXL);
__mock int match_nvdimm_bridge(struct device *dev, const void *data)
{
return is_cxl_nvdimm_bridge(dev);
}
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd) struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
{ {
...@@ -65,7 +71,7 @@ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd) ...@@ -65,7 +71,7 @@ struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd)
return NULL; return NULL;
return to_cxl_nvdimm_bridge(dev); return to_cxl_nvdimm_bridge(dev);
} }
EXPORT_SYMBOL_GPL(cxl_find_nvdimm_bridge); EXPORT_SYMBOL_NS_GPL(cxl_find_nvdimm_bridge, CXL);
static struct cxl_nvdimm_bridge * static struct cxl_nvdimm_bridge *
cxl_nvdimm_bridge_alloc(struct cxl_port *port) cxl_nvdimm_bridge_alloc(struct cxl_port *port)
...@@ -167,7 +173,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, ...@@ -167,7 +173,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
put_device(dev); put_device(dev);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm_bridge); EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm_bridge, CXL);
static void cxl_nvdimm_release(struct device *dev) static void cxl_nvdimm_release(struct device *dev)
{ {
...@@ -191,7 +197,7 @@ bool is_cxl_nvdimm(struct device *dev) ...@@ -191,7 +197,7 @@ bool is_cxl_nvdimm(struct device *dev)
{ {
return dev->type == &cxl_nvdimm_type; return dev->type == &cxl_nvdimm_type;
} }
EXPORT_SYMBOL_GPL(is_cxl_nvdimm); EXPORT_SYMBOL_NS_GPL(is_cxl_nvdimm, CXL);
struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev)
{ {
...@@ -200,7 +206,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev) ...@@ -200,7 +206,7 @@ struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev)
return NULL; return NULL;
return container_of(dev, struct cxl_nvdimm, dev); return container_of(dev, struct cxl_nvdimm, dev);
} }
EXPORT_SYMBOL_GPL(to_cxl_nvdimm); EXPORT_SYMBOL_NS_GPL(to_cxl_nvdimm, CXL);
static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd) static struct cxl_nvdimm *cxl_nvdimm_alloc(struct cxl_memdev *cxlmd)
{ {
...@@ -262,4 +268,4 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd) ...@@ -262,4 +268,4 @@ int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd)
put_device(dev); put_device(dev);
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(devm_cxl_add_nvdimm); EXPORT_SYMBOL_NS_GPL(devm_cxl_add_nvdimm, CXL);
...@@ -90,7 +90,7 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base, ...@@ -90,7 +90,7 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base,
} }
} }
} }
EXPORT_SYMBOL_GPL(cxl_probe_component_regs); EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL);
/** /**
* cxl_probe_device_regs() - Detect CXL Device register blocks * cxl_probe_device_regs() - Detect CXL Device register blocks
...@@ -156,7 +156,7 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base, ...@@ -156,7 +156,7 @@ void cxl_probe_device_regs(struct device *dev, void __iomem *base,
} }
} }
} }
EXPORT_SYMBOL_GPL(cxl_probe_device_regs); EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL);
static void __iomem *devm_cxl_iomap_block(struct device *dev, static void __iomem *devm_cxl_iomap_block(struct device *dev,
resource_size_t addr, resource_size_t addr,
...@@ -199,7 +199,7 @@ int cxl_map_component_regs(struct pci_dev *pdev, ...@@ -199,7 +199,7 @@ int cxl_map_component_regs(struct pci_dev *pdev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxl_map_component_regs); EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL);
int cxl_map_device_regs(struct pci_dev *pdev, int cxl_map_device_regs(struct pci_dev *pdev,
struct cxl_device_regs *regs, struct cxl_device_regs *regs,
...@@ -246,4 +246,4 @@ int cxl_map_device_regs(struct pci_dev *pdev, ...@@ -246,4 +246,4 @@ int cxl_map_device_regs(struct pci_dev *pdev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cxl_map_device_regs); EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL);
...@@ -191,11 +191,18 @@ struct cxl_decoder { ...@@ -191,11 +191,18 @@ struct cxl_decoder {
int interleave_granularity; int interleave_granularity;
enum cxl_decoder_type target_type; enum cxl_decoder_type target_type;
unsigned long flags; unsigned long flags;
const int nr_targets; int nr_targets;
struct cxl_dport *target[]; struct cxl_dport *target[];
}; };
/**
* enum cxl_nvdimm_brige_state - state machine for managing bus rescans
* @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed
* @CXL_NVB_DEAD: Set at brige unregistration to preclude async probing
* @CXL_NVB_ONLINE: Target state after successful ->probe()
* @CXL_NVB_OFFLINE: Target state after ->remove() or failed ->probe()
*/
enum cxl_nvdimm_brige_state { enum cxl_nvdimm_brige_state {
CXL_NVB_NEW, CXL_NVB_NEW,
CXL_NVB_DEAD, CXL_NVB_DEAD,
...@@ -308,6 +315,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, ...@@ -308,6 +315,7 @@ struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
struct cxl_port *port); struct cxl_port *port);
struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm(struct device *dev); bool is_cxl_nvdimm(struct device *dev);
bool is_cxl_nvdimm_bridge(struct device *dev);
int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd);
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd); struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd);
......
...@@ -33,13 +33,13 @@ ...@@ -33,13 +33,13 @@
* struct cxl_memdev - CXL bus object representing a Type-3 Memory Device * struct cxl_memdev - CXL bus object representing a Type-3 Memory Device
* @dev: driver core device object * @dev: driver core device object
* @cdev: char dev core object for ioctl operations * @cdev: char dev core object for ioctl operations
* @cxlm: pointer to the parent device driver data * @cxlds: The device state backing this device
* @id: id number of this memdev instance. * @id: id number of this memdev instance.
*/ */
struct cxl_memdev { struct cxl_memdev {
struct device dev; struct device dev;
struct cdev cdev; struct cdev cdev;
struct cxl_mem *cxlm; struct cxl_dev_state *cxlds;
int id; int id;
}; };
...@@ -48,7 +48,7 @@ static inline struct cxl_memdev *to_cxl_memdev(struct device *dev) ...@@ -48,7 +48,7 @@ static inline struct cxl_memdev *to_cxl_memdev(struct device *dev)
return container_of(dev, struct cxl_memdev, dev); return container_of(dev, struct cxl_memdev, dev);
} }
struct cxl_memdev *devm_cxl_add_memdev(struct cxl_mem *cxlm); struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds);
/** /**
* struct cxl_mbox_cmd - A command to be submitted to hardware. * struct cxl_mbox_cmd - A command to be submitted to hardware.
...@@ -90,9 +90,13 @@ struct cxl_mbox_cmd { ...@@ -90,9 +90,13 @@ struct cxl_mbox_cmd {
#define CXL_CAPACITY_MULTIPLIER SZ_256M #define CXL_CAPACITY_MULTIPLIER SZ_256M
/** /**
* struct cxl_mem - A CXL memory device * struct cxl_dev_state - The driver device state
* @dev: The device associated with this CXL device. *
* @cxlmd: Logical memory device chardev / interface * cxl_dev_state represents the CXL driver/device state. It provides an
* interface to mailbox commands as well as some cached data about the device.
* Currently only memory devices are represented.
*
* @dev: The device associated with this CXL state
* @regs: Parsed register blocks * @regs: Parsed register blocks
* @payload_size: Size of space for payload * @payload_size: Size of space for payload
* (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register) * (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
...@@ -117,9 +121,8 @@ struct cxl_mbox_cmd { ...@@ -117,9 +121,8 @@ struct cxl_mbox_cmd {
* See section 8.2.9.5.2 Capacity Configuration and Label Storage for * See section 8.2.9.5.2 Capacity Configuration and Label Storage for
* details on capacity parameters. * details on capacity parameters.
*/ */
struct cxl_mem { struct cxl_dev_state {
struct device *dev; struct device *dev;
struct cxl_memdev *cxlmd;
struct cxl_regs regs; struct cxl_regs regs;
...@@ -142,7 +145,7 @@ struct cxl_mem { ...@@ -142,7 +145,7 @@ struct cxl_mem {
u64 next_volatile_bytes; u64 next_volatile_bytes;
u64 next_persistent_bytes; u64 next_persistent_bytes;
int (*mbox_send)(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd); int (*mbox_send)(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd);
}; };
enum cxl_opcode { enum cxl_opcode {
...@@ -253,12 +256,12 @@ struct cxl_mem_command { ...@@ -253,12 +256,12 @@ struct cxl_mem_command {
#define CXL_CMD_FLAG_FORCE_ENABLE BIT(0) #define CXL_CMD_FLAG_FORCE_ENABLE BIT(0)
}; };
int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode, void *in, int cxl_mbox_send_cmd(struct cxl_dev_state *cxlds, u16 opcode, void *in,
size_t in_size, void *out, size_t out_size); size_t in_size, void *out, size_t out_size);
int cxl_mem_identify(struct cxl_mem *cxlm); int cxl_dev_state_identify(struct cxl_dev_state *cxlds);
int cxl_mem_enumerate_cmds(struct cxl_mem *cxlm); int cxl_enumerate_cmds(struct cxl_dev_state *cxlds);
int cxl_mem_create_range_info(struct cxl_mem *cxlm); int cxl_mem_create_range_info(struct cxl_dev_state *cxlds);
struct cxl_mem *cxl_mem_create(struct device *dev); struct cxl_dev_state *cxl_dev_state_create(struct device *dev);
void set_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); void set_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds);
void clear_exclusive_cxl_commands(struct cxl_mem *cxlm, unsigned long *cmds); void clear_exclusive_cxl_commands(struct cxl_dev_state *cxlds, unsigned long *cmds);
#endif /* __CXL_MEM_H__ */ #endif /* __CXL_MEM_H__ */
...@@ -28,39 +28,39 @@ ...@@ -28,39 +28,39 @@
* - Registers a CXL mailbox with cxl_core. * - Registers a CXL mailbox with cxl_core.
*/ */
#define cxl_doorbell_busy(cxlm) \ #define cxl_doorbell_busy(cxlds) \
(readl((cxlm)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \ (readl((cxlds)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \
CXLDEV_MBOX_CTRL_DOORBELL) CXLDEV_MBOX_CTRL_DOORBELL)
/* CXL 2.0 - 8.2.8.4 */ /* CXL 2.0 - 8.2.8.4 */
#define CXL_MAILBOX_TIMEOUT_MS (2 * HZ) #define CXL_MAILBOX_TIMEOUT_MS (2 * HZ)
static int cxl_pci_mbox_wait_for_doorbell(struct cxl_mem *cxlm) static int cxl_pci_mbox_wait_for_doorbell(struct cxl_dev_state *cxlds)
{ {
const unsigned long start = jiffies; const unsigned long start = jiffies;
unsigned long end = start; unsigned long end = start;
while (cxl_doorbell_busy(cxlm)) { while (cxl_doorbell_busy(cxlds)) {
end = jiffies; end = jiffies;
if (time_after(end, start + CXL_MAILBOX_TIMEOUT_MS)) { if (time_after(end, start + CXL_MAILBOX_TIMEOUT_MS)) {
/* Check again in case preempted before timeout test */ /* Check again in case preempted before timeout test */
if (!cxl_doorbell_busy(cxlm)) if (!cxl_doorbell_busy(cxlds))
break; break;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
cpu_relax(); cpu_relax();
} }
dev_dbg(cxlm->dev, "Doorbell wait took %dms", dev_dbg(cxlds->dev, "Doorbell wait took %dms",
jiffies_to_msecs(end) - jiffies_to_msecs(start)); jiffies_to_msecs(end) - jiffies_to_msecs(start));
return 0; return 0;
} }
static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm, static void cxl_pci_mbox_timeout(struct cxl_dev_state *cxlds,
struct cxl_mbox_cmd *mbox_cmd) struct cxl_mbox_cmd *mbox_cmd)
{ {
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
dev_dbg(dev, "Mailbox command (opcode: %#x size: %zub) timed out\n", dev_dbg(dev, "Mailbox command (opcode: %#x size: %zub) timed out\n",
mbox_cmd->opcode, mbox_cmd->size_in); mbox_cmd->opcode, mbox_cmd->size_in);
...@@ -68,7 +68,7 @@ static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm, ...@@ -68,7 +68,7 @@ static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm,
/** /**
* __cxl_pci_mbox_send_cmd() - Execute a mailbox command * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
* @cxlm: The CXL memory device to communicate with. * @cxlds: The device state to communicate with.
* @mbox_cmd: Command to send to the memory device. * @mbox_cmd: Command to send to the memory device.
* *
* Context: Any context. Expects mbox_mutex to be held. * Context: Any context. Expects mbox_mutex to be held.
...@@ -88,16 +88,16 @@ static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm, ...@@ -88,16 +88,16 @@ static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm,
* not need to coordinate with each other. The driver only uses the primary * not need to coordinate with each other. The driver only uses the primary
* mailbox. * mailbox.
*/ */
static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, static int __cxl_pci_mbox_send_cmd(struct cxl_dev_state *cxlds,
struct cxl_mbox_cmd *mbox_cmd) struct cxl_mbox_cmd *mbox_cmd)
{ {
void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET; void __iomem *payload = cxlds->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET;
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
u64 cmd_reg, status_reg; u64 cmd_reg, status_reg;
size_t out_len; size_t out_len;
int rc; int rc;
lockdep_assert_held(&cxlm->mbox_mutex); lockdep_assert_held(&cxlds->mbox_mutex);
/* /*
* Here are the steps from 8.2.8.4 of the CXL 2.0 spec. * Here are the steps from 8.2.8.4 of the CXL 2.0 spec.
...@@ -117,7 +117,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, ...@@ -117,7 +117,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
*/ */
/* #1 */ /* #1 */
if (cxl_doorbell_busy(cxlm)) { if (cxl_doorbell_busy(cxlds)) {
dev_err_ratelimited(dev, "Mailbox re-busy after acquiring\n"); dev_err_ratelimited(dev, "Mailbox re-busy after acquiring\n");
return -EBUSY; return -EBUSY;
} }
...@@ -134,22 +134,22 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, ...@@ -134,22 +134,22 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
} }
/* #2, #3 */ /* #2, #3 */
writeq(cmd_reg, cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); writeq(cmd_reg, cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
/* #4 */ /* #4 */
dev_dbg(dev, "Sending command\n"); dev_dbg(dev, "Sending command\n");
writel(CXLDEV_MBOX_CTRL_DOORBELL, writel(CXLDEV_MBOX_CTRL_DOORBELL,
cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET); cxlds->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
/* #5 */ /* #5 */
rc = cxl_pci_mbox_wait_for_doorbell(cxlm); rc = cxl_pci_mbox_wait_for_doorbell(cxlds);
if (rc == -ETIMEDOUT) { if (rc == -ETIMEDOUT) {
cxl_pci_mbox_timeout(cxlm, mbox_cmd); cxl_pci_mbox_timeout(cxlds, mbox_cmd);
return rc; return rc;
} }
/* #6 */ /* #6 */
status_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET); status_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET);
mbox_cmd->return_code = mbox_cmd->return_code =
FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg); FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg);
...@@ -159,7 +159,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, ...@@ -159,7 +159,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
} }
/* #7 */ /* #7 */
cmd_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET); cmd_reg = readq(cxlds->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg); out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
/* #8 */ /* #8 */
...@@ -171,7 +171,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, ...@@ -171,7 +171,7 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
* have requested less data than the hardware supplied even * have requested less data than the hardware supplied even
* within spec. * within spec.
*/ */
size_t n = min3(mbox_cmd->size_out, cxlm->payload_size, out_len); size_t n = min3(mbox_cmd->size_out, cxlds->payload_size, out_len);
memcpy_fromio(mbox_cmd->payload_out, payload, n); memcpy_fromio(mbox_cmd->payload_out, payload, n);
mbox_cmd->size_out = n; mbox_cmd->size_out = n;
...@@ -184,18 +184,18 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm, ...@@ -184,18 +184,18 @@ static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
/** /**
* cxl_pci_mbox_get() - Acquire exclusive access to the mailbox. * cxl_pci_mbox_get() - Acquire exclusive access to the mailbox.
* @cxlm: The memory device to gain access to. * @cxlds: The device state to gain access to.
* *
* Context: Any context. Takes the mbox_mutex. * Context: Any context. Takes the mbox_mutex.
* Return: 0 if exclusive access was acquired. * Return: 0 if exclusive access was acquired.
*/ */
static int cxl_pci_mbox_get(struct cxl_mem *cxlm) static int cxl_pci_mbox_get(struct cxl_dev_state *cxlds)
{ {
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
u64 md_status; u64 md_status;
int rc; int rc;
mutex_lock_io(&cxlm->mbox_mutex); mutex_lock_io(&cxlds->mbox_mutex);
/* /*
* XXX: There is some amount of ambiguity in the 2.0 version of the spec * XXX: There is some amount of ambiguity in the 2.0 version of the spec
...@@ -214,13 +214,13 @@ static int cxl_pci_mbox_get(struct cxl_mem *cxlm) ...@@ -214,13 +214,13 @@ static int cxl_pci_mbox_get(struct cxl_mem *cxlm)
* Mailbox Interface Ready bit. Therefore, waiting for the doorbell * Mailbox Interface Ready bit. Therefore, waiting for the doorbell
* to be ready is sufficient. * to be ready is sufficient.
*/ */
rc = cxl_pci_mbox_wait_for_doorbell(cxlm); rc = cxl_pci_mbox_wait_for_doorbell(cxlds);
if (rc) { if (rc) {
dev_warn(dev, "Mailbox interface not ready\n"); dev_warn(dev, "Mailbox interface not ready\n");
goto out; goto out;
} }
md_status = readq(cxlm->regs.memdev + CXLMDEV_STATUS_OFFSET); md_status = readq(cxlds->regs.memdev + CXLMDEV_STATUS_OFFSET);
if (!(md_status & CXLMDEV_MBOX_IF_READY && CXLMDEV_READY(md_status))) { if (!(md_status & CXLMDEV_MBOX_IF_READY && CXLMDEV_READY(md_status))) {
dev_err(dev, "mbox: reported doorbell ready, but not mbox ready\n"); dev_err(dev, "mbox: reported doorbell ready, but not mbox ready\n");
rc = -EBUSY; rc = -EBUSY;
...@@ -249,41 +249,41 @@ static int cxl_pci_mbox_get(struct cxl_mem *cxlm) ...@@ -249,41 +249,41 @@ static int cxl_pci_mbox_get(struct cxl_mem *cxlm)
return 0; return 0;
out: out:
mutex_unlock(&cxlm->mbox_mutex); mutex_unlock(&cxlds->mbox_mutex);
return rc; return rc;
} }
/** /**
* cxl_pci_mbox_put() - Release exclusive access to the mailbox. * cxl_pci_mbox_put() - Release exclusive access to the mailbox.
* @cxlm: The CXL memory device to communicate with. * @cxlds: The device state to communicate with.
* *
* Context: Any context. Expects mbox_mutex to be held. * Context: Any context. Expects mbox_mutex to be held.
*/ */
static void cxl_pci_mbox_put(struct cxl_mem *cxlm) static void cxl_pci_mbox_put(struct cxl_dev_state *cxlds)
{ {
mutex_unlock(&cxlm->mbox_mutex); mutex_unlock(&cxlds->mbox_mutex);
} }
static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int cxl_pci_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{ {
int rc; int rc;
rc = cxl_pci_mbox_get(cxlm); rc = cxl_pci_mbox_get(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = __cxl_pci_mbox_send_cmd(cxlm, cmd); rc = __cxl_pci_mbox_send_cmd(cxlds, cmd);
cxl_pci_mbox_put(cxlm); cxl_pci_mbox_put(cxlds);
return rc; return rc;
} }
static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm) static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds)
{ {
const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET);
cxlm->mbox_send = cxl_pci_mbox_send; cxlds->mbox_send = cxl_pci_mbox_send;
cxlm->payload_size = cxlds->payload_size =
1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap); 1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap);
/* /*
...@@ -293,15 +293,15 @@ static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm) ...@@ -293,15 +293,15 @@ static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm)
* there's no point in going forward. If the size is too large, there's * there's no point in going forward. If the size is too large, there's
* no harm is soft limiting it. * no harm is soft limiting it.
*/ */
cxlm->payload_size = min_t(size_t, cxlm->payload_size, SZ_1M); cxlds->payload_size = min_t(size_t, cxlds->payload_size, SZ_1M);
if (cxlm->payload_size < 256) { if (cxlds->payload_size < 256) {
dev_err(cxlm->dev, "Mailbox is too small (%zub)", dev_err(cxlds->dev, "Mailbox is too small (%zub)",
cxlm->payload_size); cxlds->payload_size);
return -ENXIO; return -ENXIO;
} }
dev_dbg(cxlm->dev, "Mailbox payload sized %zu", dev_dbg(cxlds->dev, "Mailbox payload sized %zu",
cxlm->payload_size); cxlds->payload_size);
return 0; return 0;
} }
...@@ -379,18 +379,18 @@ static int cxl_probe_regs(struct pci_dev *pdev, struct cxl_register_map *map) ...@@ -379,18 +379,18 @@ static int cxl_probe_regs(struct pci_dev *pdev, struct cxl_register_map *map)
return 0; return 0;
} }
static int cxl_map_regs(struct cxl_mem *cxlm, struct cxl_register_map *map) static int cxl_map_regs(struct cxl_dev_state *cxlds, struct cxl_register_map *map)
{ {
struct device *dev = cxlm->dev; struct device *dev = cxlds->dev;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
switch (map->reg_type) { switch (map->reg_type) {
case CXL_REGLOC_RBI_COMPONENT: case CXL_REGLOC_RBI_COMPONENT:
cxl_map_component_regs(pdev, &cxlm->regs.component, map); cxl_map_component_regs(pdev, &cxlds->regs.component, map);
dev_dbg(dev, "Mapping component registers...\n"); dev_dbg(dev, "Mapping component registers...\n");
break; break;
case CXL_REGLOC_RBI_MEMDEV: case CXL_REGLOC_RBI_MEMDEV:
cxl_map_device_regs(pdev, &cxlm->regs.device_regs, map); cxl_map_device_regs(pdev, &cxlds->regs.device_regs, map);
dev_dbg(dev, "Probing device registers...\n"); dev_dbg(dev, "Probing device registers...\n");
break; break;
default: default:
...@@ -475,7 +475,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -475,7 +475,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
struct cxl_register_map map; struct cxl_register_map map;
struct cxl_memdev *cxlmd; struct cxl_memdev *cxlmd;
struct cxl_mem *cxlm; struct cxl_dev_state *cxlds;
int rc; int rc;
/* /*
...@@ -489,39 +489,39 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -489,39 +489,39 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (rc) if (rc)
return rc; return rc;
cxlm = cxl_mem_create(&pdev->dev); cxlds = cxl_dev_state_create(&pdev->dev);
if (IS_ERR(cxlm)) if (IS_ERR(cxlds))
return PTR_ERR(cxlm); return PTR_ERR(cxlds);
rc = cxl_setup_regs(pdev, CXL_REGLOC_RBI_MEMDEV, &map); rc = cxl_setup_regs(pdev, CXL_REGLOC_RBI_MEMDEV, &map);
if (rc) if (rc)
return rc; return rc;
rc = cxl_map_regs(cxlm, &map); rc = cxl_map_regs(cxlds, &map);
if (rc) if (rc)
return rc; return rc;
rc = cxl_pci_setup_mailbox(cxlm); rc = cxl_pci_setup_mailbox(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = cxl_mem_enumerate_cmds(cxlm); rc = cxl_enumerate_cmds(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = cxl_mem_identify(cxlm); rc = cxl_dev_state_identify(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = cxl_mem_create_range_info(cxlm); rc = cxl_mem_create_range_info(cxlds);
if (rc) if (rc)
return rc; return rc;
cxlmd = devm_cxl_add_memdev(cxlm); cxlmd = devm_cxl_add_memdev(cxlds);
if (IS_ERR(cxlmd)) if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd); return PTR_ERR(cxlmd);
if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd); rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
return rc; return rc;
......
...@@ -19,9 +19,9 @@ static struct workqueue_struct *cxl_pmem_wq; ...@@ -19,9 +19,9 @@ static struct workqueue_struct *cxl_pmem_wq;
static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX); static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
static void clear_exclusive(void *cxlm) static void clear_exclusive(void *cxlds)
{ {
clear_exclusive_cxl_commands(cxlm, exclusive_cmds); clear_exclusive_cxl_commands(cxlds, exclusive_cmds);
} }
static void unregister_nvdimm(void *nvdimm) static void unregister_nvdimm(void *nvdimm)
...@@ -34,7 +34,7 @@ static int cxl_nvdimm_probe(struct device *dev) ...@@ -34,7 +34,7 @@ static int cxl_nvdimm_probe(struct device *dev)
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev); struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
unsigned long flags = 0, cmd_mask = 0; unsigned long flags = 0, cmd_mask = 0;
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
struct cxl_nvdimm_bridge *cxl_nvb; struct cxl_nvdimm_bridge *cxl_nvb;
struct nvdimm *nvdimm; struct nvdimm *nvdimm;
int rc; int rc;
...@@ -49,8 +49,8 @@ static int cxl_nvdimm_probe(struct device *dev) ...@@ -49,8 +49,8 @@ static int cxl_nvdimm_probe(struct device *dev)
goto out; goto out;
} }
set_exclusive_cxl_commands(cxlm, exclusive_cmds); set_exclusive_cxl_commands(cxlds, exclusive_cmds);
rc = devm_add_action_or_reset(dev, clear_exclusive, cxlm); rc = devm_add_action_or_reset(dev, clear_exclusive, cxlds);
if (rc) if (rc)
goto out; goto out;
...@@ -80,7 +80,7 @@ static struct cxl_driver cxl_nvdimm_driver = { ...@@ -80,7 +80,7 @@ static struct cxl_driver cxl_nvdimm_driver = {
.id = CXL_DEVICE_NVDIMM, .id = CXL_DEVICE_NVDIMM,
}; };
static int cxl_pmem_get_config_size(struct cxl_mem *cxlm, static int cxl_pmem_get_config_size(struct cxl_dev_state *cxlds,
struct nd_cmd_get_config_size *cmd, struct nd_cmd_get_config_size *cmd,
unsigned int buf_len) unsigned int buf_len)
{ {
...@@ -88,14 +88,14 @@ static int cxl_pmem_get_config_size(struct cxl_mem *cxlm, ...@@ -88,14 +88,14 @@ static int cxl_pmem_get_config_size(struct cxl_mem *cxlm,
return -EINVAL; return -EINVAL;
*cmd = (struct nd_cmd_get_config_size) { *cmd = (struct nd_cmd_get_config_size) {
.config_size = cxlm->lsa_size, .config_size = cxlds->lsa_size,
.max_xfer = cxlm->payload_size, .max_xfer = cxlds->payload_size,
}; };
return 0; return 0;
} }
static int cxl_pmem_get_config_data(struct cxl_mem *cxlm, static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
struct nd_cmd_get_config_data_hdr *cmd, struct nd_cmd_get_config_data_hdr *cmd,
unsigned int buf_len) unsigned int buf_len)
{ {
...@@ -112,15 +112,14 @@ static int cxl_pmem_get_config_data(struct cxl_mem *cxlm, ...@@ -112,15 +112,14 @@ static int cxl_pmem_get_config_data(struct cxl_mem *cxlm,
.length = cmd->in_length, .length = cmd->in_length,
}; };
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_GET_LSA, &get_lsa, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa,
sizeof(get_lsa), cmd->out_buf, sizeof(get_lsa), cmd->out_buf, cmd->in_length);
cmd->in_length);
cmd->status = 0; cmd->status = 0;
return rc; return rc;
} }
static int cxl_pmem_set_config_data(struct cxl_mem *cxlm, static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
struct nd_cmd_set_config_hdr *cmd, struct nd_cmd_set_config_hdr *cmd,
unsigned int buf_len) unsigned int buf_len)
{ {
...@@ -144,7 +143,7 @@ static int cxl_pmem_set_config_data(struct cxl_mem *cxlm, ...@@ -144,7 +143,7 @@ static int cxl_pmem_set_config_data(struct cxl_mem *cxlm,
}; };
memcpy(set_lsa->data, cmd->in_buf, cmd->in_length); memcpy(set_lsa->data, cmd->in_buf, cmd->in_length);
rc = cxl_mem_mbox_send_cmd(cxlm, CXL_MBOX_OP_SET_LSA, set_lsa, rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_SET_LSA, set_lsa,
struct_size(set_lsa, data, cmd->in_length), struct_size(set_lsa, data, cmd->in_length),
NULL, 0); NULL, 0);
...@@ -164,18 +163,18 @@ static int cxl_pmem_nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd, ...@@ -164,18 +163,18 @@ static int cxl_pmem_nvdimm_ctl(struct nvdimm *nvdimm, unsigned int cmd,
struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm); struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm); unsigned long cmd_mask = nvdimm_cmd_mask(nvdimm);
struct cxl_memdev *cxlmd = cxl_nvd->cxlmd; struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
struct cxl_mem *cxlm = cxlmd->cxlm; struct cxl_dev_state *cxlds = cxlmd->cxlds;
if (!test_bit(cmd, &cmd_mask)) if (!test_bit(cmd, &cmd_mask))
return -ENOTTY; return -ENOTTY;
switch (cmd) { switch (cmd) {
case ND_CMD_GET_CONFIG_SIZE: case ND_CMD_GET_CONFIG_SIZE:
return cxl_pmem_get_config_size(cxlm, buf, buf_len); return cxl_pmem_get_config_size(cxlds, buf, buf_len);
case ND_CMD_GET_CONFIG_DATA: case ND_CMD_GET_CONFIG_DATA:
return cxl_pmem_get_config_data(cxlm, buf, buf_len); return cxl_pmem_get_config_data(cxlds, buf, buf_len);
case ND_CMD_SET_CONFIG_DATA: case ND_CMD_SET_CONFIG_DATA:
return cxl_pmem_set_config_data(cxlm, buf, buf_len); return cxl_pmem_set_config_data(cxlds, buf, buf_len);
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -266,14 +265,24 @@ static void cxl_nvb_update_state(struct work_struct *work) ...@@ -266,14 +265,24 @@ static void cxl_nvb_update_state(struct work_struct *work)
put_device(&cxl_nvb->dev); put_device(&cxl_nvb->dev);
} }
static void cxl_nvdimm_bridge_state_work(struct cxl_nvdimm_bridge *cxl_nvb)
{
/*
* Take a reference that the workqueue will drop if new work
* gets queued.
*/
get_device(&cxl_nvb->dev);
if (!queue_work(cxl_pmem_wq, &cxl_nvb->state_work))
put_device(&cxl_nvb->dev);
}
static void cxl_nvdimm_bridge_remove(struct device *dev) static void cxl_nvdimm_bridge_remove(struct device *dev)
{ {
struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev); struct cxl_nvdimm_bridge *cxl_nvb = to_cxl_nvdimm_bridge(dev);
if (cxl_nvb->state == CXL_NVB_ONLINE) if (cxl_nvb->state == CXL_NVB_ONLINE)
cxl_nvb->state = CXL_NVB_OFFLINE; cxl_nvb->state = CXL_NVB_OFFLINE;
if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work)) cxl_nvdimm_bridge_state_work(cxl_nvb);
get_device(&cxl_nvb->dev);
} }
static int cxl_nvdimm_bridge_probe(struct device *dev) static int cxl_nvdimm_bridge_probe(struct device *dev)
...@@ -294,8 +303,7 @@ static int cxl_nvdimm_bridge_probe(struct device *dev) ...@@ -294,8 +303,7 @@ static int cxl_nvdimm_bridge_probe(struct device *dev)
} }
cxl_nvb->state = CXL_NVB_ONLINE; cxl_nvb->state = CXL_NVB_ONLINE;
if (queue_work(cxl_pmem_wq, &cxl_nvb->state_work)) cxl_nvdimm_bridge_state_work(cxl_nvb);
get_device(&cxl_nvb->dev);
return 0; return 0;
} }
...@@ -307,6 +315,31 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = { ...@@ -307,6 +315,31 @@ static struct cxl_driver cxl_nvdimm_bridge_driver = {
.id = CXL_DEVICE_NVDIMM_BRIDGE, .id = CXL_DEVICE_NVDIMM_BRIDGE,
}; };
/*
* Return all bridges to the CXL_NVB_NEW state to invalidate any
* ->state_work referring to the now destroyed cxl_pmem_wq.
*/
static int cxl_nvdimm_bridge_reset(struct device *dev, void *data)
{
struct cxl_nvdimm_bridge *cxl_nvb;
if (!is_cxl_nvdimm_bridge(dev))
return 0;
cxl_nvb = to_cxl_nvdimm_bridge(dev);
device_lock(dev);
cxl_nvb->state = CXL_NVB_NEW;
device_unlock(dev);
return 0;
}
static void destroy_cxl_pmem_wq(void)
{
destroy_workqueue(cxl_pmem_wq);
bus_for_each_dev(&cxl_bus_type, NULL, NULL, cxl_nvdimm_bridge_reset);
}
static __init int cxl_pmem_init(void) static __init int cxl_pmem_init(void)
{ {
int rc; int rc;
...@@ -332,7 +365,7 @@ static __init int cxl_pmem_init(void) ...@@ -332,7 +365,7 @@ static __init int cxl_pmem_init(void)
err_nvdimm: err_nvdimm:
cxl_driver_unregister(&cxl_nvdimm_bridge_driver); cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
err_bridge: err_bridge:
destroy_workqueue(cxl_pmem_wq); destroy_cxl_pmem_wq();
return rc; return rc;
} }
...@@ -340,7 +373,7 @@ static __exit void cxl_pmem_exit(void) ...@@ -340,7 +373,7 @@ static __exit void cxl_pmem_exit(void)
{ {
cxl_driver_unregister(&cxl_nvdimm_driver); cxl_driver_unregister(&cxl_nvdimm_driver);
cxl_driver_unregister(&cxl_nvdimm_bridge_driver); cxl_driver_unregister(&cxl_nvdimm_bridge_driver);
destroy_workqueue(cxl_pmem_wq); destroy_cxl_pmem_wq();
} }
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
......
...@@ -133,6 +133,7 @@ union acpi_subtable_headers { ...@@ -133,6 +133,7 @@ union acpi_subtable_headers {
struct acpi_subtable_header common; struct acpi_subtable_header common;
struct acpi_hmat_structure hmat; struct acpi_hmat_structure hmat;
struct acpi_prmt_module_header prmt; struct acpi_prmt_module_header prmt;
struct acpi_cedt_header cedt;
}; };
typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table);
...@@ -140,6 +141,9 @@ typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); ...@@ -140,6 +141,9 @@ typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table);
typedef int (*acpi_tbl_entry_handler)(union acpi_subtable_headers *header, typedef int (*acpi_tbl_entry_handler)(union acpi_subtable_headers *header,
const unsigned long end); const unsigned long end);
typedef int (*acpi_tbl_entry_handler_arg)(union acpi_subtable_headers *header,
void *arg, const unsigned long end);
/* Debugger support */ /* Debugger support */
struct acpi_debugger_ops { struct acpi_debugger_ops {
...@@ -216,6 +220,8 @@ static inline int acpi_debugger_notify_command_complete(void) ...@@ -216,6 +220,8 @@ static inline int acpi_debugger_notify_command_complete(void)
struct acpi_subtable_proc { struct acpi_subtable_proc {
int id; int id;
acpi_tbl_entry_handler handler; acpi_tbl_entry_handler handler;
acpi_tbl_entry_handler_arg handler_arg;
void *arg;
int count; int count;
}; };
...@@ -232,17 +238,31 @@ int acpi_locate_initial_tables (void); ...@@ -232,17 +238,31 @@ int acpi_locate_initial_tables (void);
void acpi_reserve_initial_tables (void); void acpi_reserve_initial_tables (void);
void acpi_table_init_complete (void); void acpi_table_init_complete (void);
int acpi_table_init (void); int acpi_table_init (void);
#ifdef CONFIG_ACPI_TABLE_LIB
#define EXPORT_SYMBOL_ACPI_LIB(x) EXPORT_SYMBOL_NS_GPL(x, ACPI)
#define __init_or_acpilib
#define __initdata_or_acpilib
#else
#define EXPORT_SYMBOL_ACPI_LIB(x)
#define __init_or_acpilib __init
#define __initdata_or_acpilib __initdata
#endif
int acpi_table_parse(char *id, acpi_tbl_table_handler handler); int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
int __init acpi_table_parse_entries(char *id, unsigned long table_size, int __init_or_acpilib acpi_table_parse_entries(char *id,
int entry_id, unsigned long table_size, int entry_id,
acpi_tbl_entry_handler handler, acpi_tbl_entry_handler handler, unsigned int max_entries);
unsigned int max_entries); int __init_or_acpilib acpi_table_parse_entries_array(char *id,
int __init acpi_table_parse_entries_array(char *id, unsigned long table_size, unsigned long table_size, struct acpi_subtable_proc *proc,
struct acpi_subtable_proc *proc, int proc_num, int proc_num, unsigned int max_entries);
unsigned int max_entries);
int acpi_table_parse_madt(enum acpi_madt_type id, int acpi_table_parse_madt(enum acpi_madt_type id,
acpi_tbl_entry_handler handler, acpi_tbl_entry_handler handler,
unsigned int max_entries); unsigned int max_entries);
int __init_or_acpilib
acpi_table_parse_cedt(enum acpi_cedt_type id,
acpi_tbl_entry_handler_arg handler_arg, void *arg);
int acpi_parse_mcfg (struct acpi_table_header *header); int acpi_parse_mcfg (struct acpi_table_header *header);
void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
ldflags-y += --wrap=acpi_table_parse_cedt
ldflags-y += --wrap=is_acpi_device_node ldflags-y += --wrap=is_acpi_device_node
ldflags-y += --wrap=acpi_get_table
ldflags-y += --wrap=acpi_put_table
ldflags-y += --wrap=acpi_evaluate_integer ldflags-y += --wrap=acpi_evaluate_integer
ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=acpi_pci_find_root
ldflags-y += --wrap=pci_walk_bus ldflags-y += --wrap=pci_walk_bus
......
...@@ -182,6 +182,13 @@ static struct { ...@@ -182,6 +182,13 @@ static struct {
}, },
}; };
struct acpi_cedt_cfmws *mock_cfmws[4] = {
[0] = &mock_cedt.cfmws0.cfmws,
[1] = &mock_cedt.cfmws1.cfmws,
[2] = &mock_cedt.cfmws2.cfmws,
[3] = &mock_cedt.cfmws3.cfmws,
};
struct cxl_mock_res { struct cxl_mock_res {
struct list_head list; struct list_head list;
struct range range; struct range range;
...@@ -232,12 +239,6 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size) ...@@ -232,12 +239,6 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size)
static int populate_cedt(void) static int populate_cedt(void)
{ {
struct acpi_cedt_cfmws *cfmws[4] = {
[0] = &mock_cedt.cfmws0.cfmws,
[1] = &mock_cedt.cfmws1.cfmws,
[2] = &mock_cedt.cfmws2.cfmws,
[3] = &mock_cedt.cfmws3.cfmws,
};
struct cxl_mock_res *res; struct cxl_mock_res *res;
int i; int i;
...@@ -257,8 +258,8 @@ static int populate_cedt(void) ...@@ -257,8 +258,8 @@ static int populate_cedt(void)
chbs->length = size; chbs->length = size;
} }
for (i = 0; i < ARRAY_SIZE(cfmws); i++) { for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
struct acpi_cedt_cfmws *window = cfmws[i]; struct acpi_cedt_cfmws *window = mock_cfmws[i];
res = alloc_mock_res(window->window_size); res = alloc_mock_res(window->window_size);
if (!res) if (!res)
...@@ -269,21 +270,44 @@ static int populate_cedt(void) ...@@ -269,21 +270,44 @@ static int populate_cedt(void)
return 0; return 0;
} }
static acpi_status mock_acpi_get_table(char *signature, u32 instance, /*
struct acpi_table_header **out_table) * WARNING, this hack assumes the format of 'struct
* cxl_cfmws_context' and 'struct cxl_chbs_context' share the property that
* the first struct member is the device being probed by the cxl_acpi
* driver.
*/
struct cxl_cedt_context {
struct device *dev;
};
static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
acpi_tbl_entry_handler_arg handler_arg,
void *arg)
{ {
if (instance < U32_MAX || strcmp(signature, ACPI_SIG_CEDT) != 0) struct cxl_cedt_context *ctx = arg;
return acpi_get_table(signature, instance, out_table); struct device *dev = ctx->dev;
union acpi_subtable_headers *h;
unsigned long end;
int i;
*out_table = (struct acpi_table_header *) &mock_cedt; if (dev != &cxl_acpi->dev)
return AE_OK; return acpi_table_parse_cedt(id, handler_arg, arg);
}
static void mock_acpi_put_table(struct acpi_table_header *table) if (id == ACPI_CEDT_TYPE_CHBS)
{ for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
if (table == (struct acpi_table_header *) &mock_cedt) h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];
return; end = (unsigned long)&mock_cedt.chbs[i + 1];
acpi_put_table(table); handler_arg(h, arg, end);
}
if (id == ACPI_CEDT_TYPE_CFMWS)
for (i = 0; i < ARRAY_SIZE(mock_cfmws); i++) {
h = (union acpi_subtable_headers *) mock_cfmws[i];
end = (unsigned long) h + mock_cfmws[i]->header.length;
handler_arg(h, arg, end);
}
return 0;
} }
static bool is_mock_bridge(struct device *dev) static bool is_mock_bridge(struct device *dev)
...@@ -388,8 +412,7 @@ static struct cxl_mock_ops cxl_mock_ops = { ...@@ -388,8 +412,7 @@ static struct cxl_mock_ops cxl_mock_ops = {
.is_mock_port = is_mock_port, .is_mock_port = is_mock_port,
.is_mock_dev = is_mock_dev, .is_mock_dev = is_mock_dev,
.mock_port = mock_cxl_root_port, .mock_port = mock_cxl_root_port,
.acpi_get_table = mock_acpi_get_table, .acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
.acpi_put_table = mock_acpi_put_table,
.acpi_evaluate_integer = mock_acpi_evaluate_integer, .acpi_evaluate_integer = mock_acpi_evaluate_integer,
.acpi_pci_find_root = mock_acpi_pci_find_root, .acpi_pci_find_root = mock_acpi_pci_find_root,
.list = LIST_HEAD_INIT(cxl_mock_ops.list), .list = LIST_HEAD_INIT(cxl_mock_ops.list),
...@@ -574,3 +597,4 @@ static __exit void cxl_test_exit(void) ...@@ -574,3 +597,4 @@ static __exit void cxl_test_exit(void)
module_init(cxl_test_init); module_init(cxl_test_init);
module_exit(cxl_test_exit); module_exit(cxl_test_exit);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(ACPI);
...@@ -28,8 +28,24 @@ static struct cxl_cel_entry mock_cel[] = { ...@@ -28,8 +28,24 @@ static struct cxl_cel_entry mock_cel[] = {
.opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA), .opcode = cpu_to_le16(CXL_MBOX_OP_SET_LSA),
.effect = cpu_to_le16(EFFECT(1) | EFFECT(2)), .effect = cpu_to_le16(EFFECT(1) | EFFECT(2)),
}, },
{
.opcode = cpu_to_le16(CXL_MBOX_OP_GET_HEALTH_INFO),
.effect = cpu_to_le16(0),
},
}; };
/* See CXL 2.0 Table 181 Get Health Info Output Payload */
struct cxl_mbox_health_info {
u8 health_status;
u8 media_status;
u8 ext_status;
u8 life_used;
__le16 temperature;
__le32 dirty_shutdowns;
__le32 volatile_errors;
__le32 pmem_errors;
} __packed;
static struct { static struct {
struct cxl_mbox_get_supported_logs gsl; struct cxl_mbox_get_supported_logs gsl;
struct cxl_gsl_entry entry; struct cxl_gsl_entry entry;
...@@ -54,7 +70,7 @@ static int mock_gsl(struct cxl_mbox_cmd *cmd) ...@@ -54,7 +70,7 @@ static int mock_gsl(struct cxl_mbox_cmd *cmd)
return 0; return 0;
} }
static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int mock_get_log(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{ {
struct cxl_mbox_get_log *gl = cmd->payload_in; struct cxl_mbox_get_log *gl = cmd->payload_in;
u32 offset = le32_to_cpu(gl->offset); u32 offset = le32_to_cpu(gl->offset);
...@@ -64,7 +80,7 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -64,7 +80,7 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
if (cmd->size_in < sizeof(*gl)) if (cmd->size_in < sizeof(*gl))
return -EINVAL; return -EINVAL;
if (length > cxlm->payload_size) if (length > cxlds->payload_size)
return -EINVAL; return -EINVAL;
if (offset + length > sizeof(mock_cel)) if (offset + length > sizeof(mock_cel))
return -EINVAL; return -EINVAL;
...@@ -78,9 +94,9 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -78,9 +94,9 @@ static int mock_get_log(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
return 0; return 0;
} }
static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int mock_id(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{ {
struct platform_device *pdev = to_platform_device(cxlm->dev); struct platform_device *pdev = to_platform_device(cxlds->dev);
struct cxl_mbox_identify id = { struct cxl_mbox_identify id = {
.fw_revision = { "mock fw v1 " }, .fw_revision = { "mock fw v1 " },
.lsa_size = cpu_to_le32(LSA_SIZE), .lsa_size = cpu_to_le32(LSA_SIZE),
...@@ -120,10 +136,10 @@ static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -120,10 +136,10 @@ static int mock_id(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
return 0; return 0;
} }
static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int mock_get_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{ {
struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in; struct cxl_mbox_get_lsa *get_lsa = cmd->payload_in;
void *lsa = dev_get_drvdata(cxlm->dev); void *lsa = dev_get_drvdata(cxlds->dev);
u32 offset, length; u32 offset, length;
if (sizeof(*get_lsa) > cmd->size_in) if (sizeof(*get_lsa) > cmd->size_in)
...@@ -139,10 +155,10 @@ static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -139,10 +155,10 @@ static int mock_get_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
return 0; return 0;
} }
static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int mock_set_lsa(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{ {
struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in; struct cxl_mbox_set_lsa *set_lsa = cmd->payload_in;
void *lsa = dev_get_drvdata(cxlm->dev); void *lsa = dev_get_drvdata(cxlds->dev);
u32 offset, length; u32 offset, length;
if (sizeof(*set_lsa) > cmd->size_in) if (sizeof(*set_lsa) > cmd->size_in)
...@@ -156,9 +172,39 @@ static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -156,9 +172,39 @@ static int mock_set_lsa(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
return 0; return 0;
} }
static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) static int mock_health_info(struct cxl_dev_state *cxlds,
struct cxl_mbox_cmd *cmd)
{ {
struct device *dev = cxlm->dev; struct cxl_mbox_health_info health_info = {
/* set flags for maint needed, perf degraded, hw replacement */
.health_status = 0x7,
/* set media status to "All Data Lost" */
.media_status = 0x3,
/*
* set ext_status flags for:
* ext_life_used: normal,
* ext_temperature: critical,
* ext_corrected_volatile: warning,
* ext_corrected_persistent: normal,
*/
.ext_status = 0x18,
.life_used = 15,
.temperature = cpu_to_le16(25),
.dirty_shutdowns = cpu_to_le32(10),
.volatile_errors = cpu_to_le32(20),
.pmem_errors = cpu_to_le32(30),
};
if (cmd->size_out < sizeof(health_info))
return -EINVAL;
memcpy(cmd->payload_out, &health_info, sizeof(health_info));
return 0;
}
static int cxl_mock_mbox_send(struct cxl_dev_state *cxlds, struct cxl_mbox_cmd *cmd)
{
struct device *dev = cxlds->dev;
int rc = -EIO; int rc = -EIO;
switch (cmd->opcode) { switch (cmd->opcode) {
...@@ -166,16 +212,19 @@ static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd) ...@@ -166,16 +212,19 @@ static int cxl_mock_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
rc = mock_gsl(cmd); rc = mock_gsl(cmd);
break; break;
case CXL_MBOX_OP_GET_LOG: case CXL_MBOX_OP_GET_LOG:
rc = mock_get_log(cxlm, cmd); rc = mock_get_log(cxlds, cmd);
break; break;
case CXL_MBOX_OP_IDENTIFY: case CXL_MBOX_OP_IDENTIFY:
rc = mock_id(cxlm, cmd); rc = mock_id(cxlds, cmd);
break; break;
case CXL_MBOX_OP_GET_LSA: case CXL_MBOX_OP_GET_LSA:
rc = mock_get_lsa(cxlm, cmd); rc = mock_get_lsa(cxlds, cmd);
break; break;
case CXL_MBOX_OP_SET_LSA: case CXL_MBOX_OP_SET_LSA:
rc = mock_set_lsa(cxlm, cmd); rc = mock_set_lsa(cxlds, cmd);
break;
case CXL_MBOX_OP_GET_HEALTH_INFO:
rc = mock_health_info(cxlds, cmd);
break; break;
default: default:
break; break;
...@@ -196,7 +245,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) ...@@ -196,7 +245,7 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct cxl_memdev *cxlmd; struct cxl_memdev *cxlmd;
struct cxl_mem *cxlm; struct cxl_dev_state *cxlds;
void *lsa; void *lsa;
int rc; int rc;
...@@ -208,30 +257,30 @@ static int cxl_mock_mem_probe(struct platform_device *pdev) ...@@ -208,30 +257,30 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
return rc; return rc;
dev_set_drvdata(dev, lsa); dev_set_drvdata(dev, lsa);
cxlm = cxl_mem_create(dev); cxlds = cxl_dev_state_create(dev);
if (IS_ERR(cxlm)) if (IS_ERR(cxlds))
return PTR_ERR(cxlm); return PTR_ERR(cxlds);
cxlm->mbox_send = cxl_mock_mbox_send; cxlds->mbox_send = cxl_mock_mbox_send;
cxlm->payload_size = SZ_4K; cxlds->payload_size = SZ_4K;
rc = cxl_mem_enumerate_cmds(cxlm); rc = cxl_enumerate_cmds(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = cxl_mem_identify(cxlm); rc = cxl_dev_state_identify(cxlds);
if (rc) if (rc)
return rc; return rc;
rc = cxl_mem_create_range_info(cxlm); rc = cxl_mem_create_range_info(cxlds);
if (rc) if (rc)
return rc; return rc;
cxlmd = devm_cxl_add_memdev(cxlm); cxlmd = devm_cxl_add_memdev(cxlds);
if (IS_ERR(cxlmd)) if (IS_ERR(cxlmd))
return PTR_ERR(cxlmd); return PTR_ERR(cxlmd);
if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM)) if (range_len(&cxlds->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
rc = devm_cxl_add_nvdimm(dev, cxlmd); rc = devm_cxl_add_nvdimm(dev, cxlmd);
return 0; return 0;
......
...@@ -58,36 +58,23 @@ bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode) ...@@ -58,36 +58,23 @@ bool __wrap_is_acpi_device_node(const struct fwnode_handle *fwnode)
} }
EXPORT_SYMBOL(__wrap_is_acpi_device_node); EXPORT_SYMBOL(__wrap_is_acpi_device_node);
acpi_status __wrap_acpi_get_table(char *signature, u32 instance, int __wrap_acpi_table_parse_cedt(enum acpi_cedt_type id,
struct acpi_table_header **out_table) acpi_tbl_entry_handler_arg handler_arg,
void *arg)
{ {
int index; int index, rc;
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
acpi_status status;
if (ops) if (ops)
status = ops->acpi_get_table(signature, instance, out_table); rc = ops->acpi_table_parse_cedt(id, handler_arg, arg);
else else
status = acpi_get_table(signature, instance, out_table); rc = acpi_table_parse_cedt(id, handler_arg, arg);
put_cxl_mock_ops(index); put_cxl_mock_ops(index);
return status; return rc;
}
EXPORT_SYMBOL(__wrap_acpi_get_table);
void __wrap_acpi_put_table(struct acpi_table_header *table)
{
int index;
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
if (ops)
ops->acpi_put_table(table);
else
acpi_put_table(table);
put_cxl_mock_ops(index);
} }
EXPORT_SYMBOL(__wrap_acpi_put_table); EXPORT_SYMBOL_NS_GPL(__wrap_acpi_table_parse_cedt, ACPI);
acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle, acpi_status __wrap_acpi_evaluate_integer(acpi_handle handle,
acpi_string pathname, acpi_string pathname,
...@@ -169,3 +156,4 @@ __wrap_nvdimm_bus_register(struct device *dev, ...@@ -169,3 +156,4 @@ __wrap_nvdimm_bus_register(struct device *dev,
EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(ACPI);
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
struct cxl_mock_ops { struct cxl_mock_ops {
struct list_head list; struct list_head list;
bool (*is_mock_adev)(struct acpi_device *dev); bool (*is_mock_adev)(struct acpi_device *dev);
acpi_status (*acpi_get_table)(char *signature, u32 instance, int (*acpi_table_parse_cedt)(enum acpi_cedt_type id,
struct acpi_table_header **out_table); acpi_tbl_entry_handler_arg handler_arg,
void (*acpi_put_table)(struct acpi_table_header *table); void *arg);
bool (*is_mock_bridge)(struct device *dev); bool (*is_mock_bridge)(struct device *dev);
acpi_status (*acpi_evaluate_integer)(acpi_handle handle, acpi_status (*acpi_evaluate_integer)(acpi_handle handle,
acpi_string pathname, acpi_string pathname,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment