1/* 2 * Copyright 2014 IBM Corp. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 10#include <linux/module.h> 11#include <linux/rcupdate.h> 12#include <asm/errno.h> 13#include <misc/cxl.h> 14#include "cxl.h" 15 16/* protected by rcu */ 17static struct cxl_calls *cxl_calls; 18 19atomic_t cxl_use_count = ATOMIC_INIT(0); 20EXPORT_SYMBOL(cxl_use_count); 21 22#ifdef CONFIG_CXL_MODULE 23 24static inline struct cxl_calls *cxl_calls_get(void) 25{ 26 struct cxl_calls *calls = NULL; 27 28 rcu_read_lock(); 29 calls = rcu_dereference(cxl_calls); 30 if (calls && !try_module_get(calls->owner)) 31 calls = NULL; 32 rcu_read_unlock(); 33 34 return calls; 35} 36 37static inline void cxl_calls_put(struct cxl_calls *calls) 38{ 39 BUG_ON(calls != cxl_calls); 40 41 /* we don't need to rcu this, as we hold a reference to the module */ 42 module_put(cxl_calls->owner); 43} 44 45#else /* !defined CONFIG_CXL_MODULE */ 46 47static inline struct cxl_calls *cxl_calls_get(void) 48{ 49 return cxl_calls; 50} 51 52static inline void cxl_calls_put(struct cxl_calls *calls) { } 53 54#endif /* CONFIG_CXL_MODULE */ 55 56void cxl_slbia(struct mm_struct *mm) 57{ 58 struct cxl_calls *calls; 59 60 calls = cxl_calls_get(); 61 if (!calls) 62 return; 63 64 if (cxl_ctx_in_use()) 65 calls->cxl_slbia(mm); 66 67 cxl_calls_put(calls); 68} 69 70int register_cxl_calls(struct cxl_calls *calls) 71{ 72 if (cxl_calls) 73 return -EBUSY; 74 75 rcu_assign_pointer(cxl_calls, calls); 76 return 0; 77} 78EXPORT_SYMBOL_GPL(register_cxl_calls); 79 80void unregister_cxl_calls(struct cxl_calls *calls) 81{ 82 BUG_ON(cxl_calls->owner != calls->owner); 83 RCU_INIT_POINTER(cxl_calls, NULL); 84 synchronize_rcu(); 85} 86EXPORT_SYMBOL_GPL(unregister_cxl_calls); 87