mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
125 lines
2.4 KiB
125 lines
2.4 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright 2014 IBM Corp. |
|
*/ |
|
|
|
#include <linux/module.h> |
|
#include <linux/rcupdate.h> |
|
#include <asm/errno.h> |
|
#include <misc/cxl-base.h> |
|
#include <linux/of_platform.h> |
|
#include "cxl.h" |
|
|
|
/* protected by rcu */ |
|
static struct cxl_calls *cxl_calls; |
|
|
|
atomic_t cxl_use_count = ATOMIC_INIT(0); |
|
EXPORT_SYMBOL(cxl_use_count); |
|
|
|
#ifdef CONFIG_CXL_MODULE |
|
|
|
static inline struct cxl_calls *cxl_calls_get(void) |
|
{ |
|
struct cxl_calls *calls = NULL; |
|
|
|
rcu_read_lock(); |
|
calls = rcu_dereference(cxl_calls); |
|
if (calls && !try_module_get(calls->owner)) |
|
calls = NULL; |
|
rcu_read_unlock(); |
|
|
|
return calls; |
|
} |
|
|
|
static inline void cxl_calls_put(struct cxl_calls *calls) |
|
{ |
|
BUG_ON(calls != cxl_calls); |
|
|
|
/* we don't need to rcu this, as we hold a reference to the module */ |
|
module_put(cxl_calls->owner); |
|
} |
|
|
|
#else /* !defined CONFIG_CXL_MODULE */ |
|
|
|
static inline struct cxl_calls *cxl_calls_get(void) |
|
{ |
|
return cxl_calls; |
|
} |
|
|
|
static inline void cxl_calls_put(struct cxl_calls *calls) { } |
|
|
|
#endif /* CONFIG_CXL_MODULE */ |
|
|
|
/* AFU refcount management */ |
|
struct cxl_afu *cxl_afu_get(struct cxl_afu *afu) |
|
{ |
|
return (get_device(&afu->dev) == NULL) ? NULL : afu; |
|
} |
|
EXPORT_SYMBOL_GPL(cxl_afu_get); |
|
|
|
void cxl_afu_put(struct cxl_afu *afu) |
|
{ |
|
put_device(&afu->dev); |
|
} |
|
EXPORT_SYMBOL_GPL(cxl_afu_put); |
|
|
|
void cxl_slbia(struct mm_struct *mm) |
|
{ |
|
struct cxl_calls *calls; |
|
|
|
calls = cxl_calls_get(); |
|
if (!calls) |
|
return; |
|
|
|
if (cxl_ctx_in_use()) |
|
calls->cxl_slbia(mm); |
|
|
|
cxl_calls_put(calls); |
|
} |
|
|
|
int register_cxl_calls(struct cxl_calls *calls) |
|
{ |
|
if (cxl_calls) |
|
return -EBUSY; |
|
|
|
rcu_assign_pointer(cxl_calls, calls); |
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(register_cxl_calls); |
|
|
|
void unregister_cxl_calls(struct cxl_calls *calls) |
|
{ |
|
BUG_ON(cxl_calls->owner != calls->owner); |
|
RCU_INIT_POINTER(cxl_calls, NULL); |
|
synchronize_rcu(); |
|
} |
|
EXPORT_SYMBOL_GPL(unregister_cxl_calls); |
|
|
|
int cxl_update_properties(struct device_node *dn, |
|
struct property *new_prop) |
|
{ |
|
return of_update_property(dn, new_prop); |
|
} |
|
EXPORT_SYMBOL_GPL(cxl_update_properties); |
|
|
|
static int __init cxl_base_init(void) |
|
{ |
|
struct device_node *np; |
|
struct platform_device *dev; |
|
int count = 0; |
|
|
|
/* |
|
* Scan for compatible devices in guest only |
|
*/ |
|
if (cpu_has_feature(CPU_FTR_HVMODE)) |
|
return 0; |
|
|
|
for_each_compatible_node(np, NULL, "ibm,coherent-platform-facility") { |
|
dev = of_platform_device_create(np, NULL, NULL); |
|
if (dev) |
|
count++; |
|
} |
|
pr_devel("Found %d cxl device(s)\n", count); |
|
return 0; |
|
} |
|
device_initcall(cxl_base_init);
|
|
|