linux/drivers/misc/cxl/base.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2014 IBM Corp.
   4 */
   5
   6#include <linux/module.h>
   7#include <linux/rcupdate.h>
   8#include <asm/errno.h>
   9#include <misc/cxl-base.h>
  10#include <linux/of_platform.h>
  11#include "cxl.h"
  12
  13/* protected by rcu */
  14static struct cxl_calls *cxl_calls;
  15
  16atomic_t cxl_use_count = ATOMIC_INIT(0);
  17EXPORT_SYMBOL(cxl_use_count);
  18
  19#ifdef CONFIG_CXL_MODULE
  20
  21static inline struct cxl_calls *cxl_calls_get(void)
  22{
  23        struct cxl_calls *calls = NULL;
  24
  25        rcu_read_lock();
  26        calls = rcu_dereference(cxl_calls);
  27        if (calls && !try_module_get(calls->owner))
  28                calls = NULL;
  29        rcu_read_unlock();
  30
  31        return calls;
  32}
  33
  34static inline void cxl_calls_put(struct cxl_calls *calls)
  35{
  36        BUG_ON(calls != cxl_calls);
  37
  38        /* we don't need to rcu this, as we hold a reference to the module */
  39        module_put(cxl_calls->owner);
  40}
  41
  42#else /* !defined CONFIG_CXL_MODULE */
  43
  44static inline struct cxl_calls *cxl_calls_get(void)
  45{
  46        return cxl_calls;
  47}
  48
  49static inline void cxl_calls_put(struct cxl_calls *calls) { }
  50
  51#endif /* CONFIG_CXL_MODULE */
  52
  53/* AFU refcount management */
  54struct cxl_afu *cxl_afu_get(struct cxl_afu *afu)
  55{
  56        return (get_device(&afu->dev) == NULL) ? NULL : afu;
  57}
  58EXPORT_SYMBOL_GPL(cxl_afu_get);
  59
  60void cxl_afu_put(struct cxl_afu *afu)
  61{
  62        put_device(&afu->dev);
  63}
  64EXPORT_SYMBOL_GPL(cxl_afu_put);
  65
  66void cxl_slbia(struct mm_struct *mm)
  67{
  68        struct cxl_calls *calls;
  69
  70        calls = cxl_calls_get();
  71        if (!calls)
  72                return;
  73
  74        if (cxl_ctx_in_use())
  75            calls->cxl_slbia(mm);
  76
  77        cxl_calls_put(calls);
  78}
  79
  80int register_cxl_calls(struct cxl_calls *calls)
  81{
  82        if (cxl_calls)
  83                return -EBUSY;
  84
  85        rcu_assign_pointer(cxl_calls, calls);
  86        return 0;
  87}
  88EXPORT_SYMBOL_GPL(register_cxl_calls);
  89
  90void unregister_cxl_calls(struct cxl_calls *calls)
  91{
  92        BUG_ON(cxl_calls->owner != calls->owner);
  93        RCU_INIT_POINTER(cxl_calls, NULL);
  94        synchronize_rcu();
  95}
  96EXPORT_SYMBOL_GPL(unregister_cxl_calls);
  97
  98int cxl_update_properties(struct device_node *dn,
  99                          struct property *new_prop)
 100{
 101        return of_update_property(dn, new_prop);
 102}
 103EXPORT_SYMBOL_GPL(cxl_update_properties);
 104
 105static int __init cxl_base_init(void)
 106{
 107        struct device_node *np;
 108        struct platform_device *dev;
 109        int count = 0;
 110
 111        /*
 112         * Scan for compatible devices in guest only
 113         */
 114        if (cpu_has_feature(CPU_FTR_HVMODE))
 115                return 0;
 116
 117        for_each_compatible_node(np, NULL, "ibm,coherent-platform-facility") {
 118                dev = of_platform_device_create(np, NULL, NULL);
 119                if (dev)
 120                        count++;
 121        }
 122        pr_devel("Found %d cxl device(s)\n", count);
 123        return 0;
 124}
 125device_initcall(cxl_base_init);
 126