cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

main.c (8991B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2014 IBM Corp.
      4 */
      5
      6#include <linux/spinlock.h>
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <linux/device.h>
     10#include <linux/mutex.h>
     11#include <linux/init.h>
     12#include <linux/list.h>
     13#include <linux/mm.h>
     14#include <linux/of.h>
     15#include <linux/slab.h>
     16#include <linux/idr.h>
     17#include <linux/pci.h>
     18#include <linux/platform_device.h>
     19#include <linux/sched/task.h>
     20
     21#include <asm/cputable.h>
     22#include <asm/mmu.h>
     23#include <misc/cxl-base.h>
     24
     25#include "cxl.h"
     26#include "trace.h"
     27
     28static DEFINE_SPINLOCK(adapter_idr_lock);
     29static DEFINE_IDR(cxl_adapter_idr);
     30
     31uint cxl_verbose;
     32module_param_named(verbose, cxl_verbose, uint, 0600);
     33MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
     34
     35const struct cxl_backend_ops *cxl_ops;
     36
     37int cxl_afu_slbia(struct cxl_afu *afu)
     38{
     39	unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
     40
     41	pr_devel("cxl_afu_slbia issuing SLBIA command\n");
     42	cxl_p2n_write(afu, CXL_SLBIA_An, CXL_TLB_SLB_IQ_ALL);
     43	while (cxl_p2n_read(afu, CXL_SLBIA_An) & CXL_TLB_SLB_P) {
     44		if (time_after_eq(jiffies, timeout)) {
     45			dev_warn(&afu->dev, "WARNING: CXL AFU SLBIA timed out!\n");
     46			return -EBUSY;
     47		}
     48		/* If the adapter has gone down, we can assume that we
     49		 * will PERST it and that will invalidate everything.
     50		 */
     51		if (!cxl_ops->link_ok(afu->adapter, afu))
     52			return -EIO;
     53		cpu_relax();
     54	}
     55	return 0;
     56}
     57
     58static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
     59{
     60	unsigned long flags;
     61
     62	if (ctx->mm != mm)
     63		return;
     64
     65	pr_devel("%s matched mm - card: %i afu: %i pe: %i\n", __func__,
     66		 ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe);
     67
     68	spin_lock_irqsave(&ctx->sste_lock, flags);
     69	trace_cxl_slbia(ctx);
     70	memset(ctx->sstp, 0, ctx->sst_size);
     71	spin_unlock_irqrestore(&ctx->sste_lock, flags);
     72	mb();
     73	cxl_afu_slbia(ctx->afu);
     74}
     75
     76static inline void cxl_slbia_core(struct mm_struct *mm)
     77{
     78	struct cxl *adapter;
     79	struct cxl_afu *afu;
     80	struct cxl_context *ctx;
     81	int card, slice, id;
     82
     83	pr_devel("%s called\n", __func__);
     84
     85	spin_lock(&adapter_idr_lock);
     86	idr_for_each_entry(&cxl_adapter_idr, adapter, card) {
     87		/* XXX: Make this lookup faster with link from mm to ctx */
     88		spin_lock(&adapter->afu_list_lock);
     89		for (slice = 0; slice < adapter->slices; slice++) {
     90			afu = adapter->afu[slice];
     91			if (!afu || !afu->enabled)
     92				continue;
     93			rcu_read_lock();
     94			idr_for_each_entry(&afu->contexts_idr, ctx, id)
     95				_cxl_slbia(ctx, mm);
     96			rcu_read_unlock();
     97		}
     98		spin_unlock(&adapter->afu_list_lock);
     99	}
    100	spin_unlock(&adapter_idr_lock);
    101}
    102
    103static struct cxl_calls cxl_calls = {
    104	.cxl_slbia = cxl_slbia_core,
    105	.owner = THIS_MODULE,
    106};
    107
    108int cxl_alloc_sst(struct cxl_context *ctx)
    109{
    110	unsigned long vsid;
    111	u64 ea_mask, size, sstp0, sstp1;
    112
    113	sstp0 = 0;
    114	sstp1 = 0;
    115
    116	ctx->sst_size = PAGE_SIZE;
    117	ctx->sst_lru = 0;
    118	ctx->sstp = (struct cxl_sste *)get_zeroed_page(GFP_KERNEL);
    119	if (!ctx->sstp) {
    120		pr_err("cxl_alloc_sst: Unable to allocate segment table\n");
    121		return -ENOMEM;
    122	}
    123	pr_devel("SSTP allocated at 0x%p\n", ctx->sstp);
    124
    125	vsid  = get_kernel_vsid((u64)ctx->sstp, mmu_kernel_ssize) << 12;
    126
    127	sstp0 |= (u64)mmu_kernel_ssize << CXL_SSTP0_An_B_SHIFT;
    128	sstp0 |= (SLB_VSID_KERNEL | mmu_psize_defs[mmu_linear_psize].sllp) << 50;
    129
    130	size = (((u64)ctx->sst_size >> 8) - 1) << CXL_SSTP0_An_SegTableSize_SHIFT;
    131	if (unlikely(size & ~CXL_SSTP0_An_SegTableSize_MASK)) {
    132		WARN(1, "Impossible segment table size\n");
    133		return -EINVAL;
    134	}
    135	sstp0 |= size;
    136
    137	if (mmu_kernel_ssize == MMU_SEGSIZE_256M)
    138		ea_mask = 0xfffff00ULL;
    139	else
    140		ea_mask = 0xffffffff00ULL;
    141
    142	sstp0 |=  vsid >>     (50-14);  /*   Top 14 bits of VSID */
    143	sstp1 |= (vsid << (64-(50-14))) & ~ea_mask;
    144	sstp1 |= (u64)ctx->sstp & ea_mask;
    145	sstp1 |= CXL_SSTP1_An_V;
    146
    147	pr_devel("Looked up %#llx: slbfee. %#llx (ssize: %x, vsid: %#lx), copied to SSTP0: %#llx, SSTP1: %#llx\n",
    148			(u64)ctx->sstp, (u64)ctx->sstp & ESID_MASK, mmu_kernel_ssize, vsid, sstp0, sstp1);
    149
    150	/* Store calculated sstp hardware points for use later */
    151	ctx->sstp0 = sstp0;
    152	ctx->sstp1 = sstp1;
    153
    154	return 0;
    155}
    156
    157/* print buffer content as integers when debugging */
    158void cxl_dump_debug_buffer(void *buf, size_t buf_len)
    159{
    160#ifdef DEBUG
    161	int i, *ptr;
    162
    163	/*
    164	 * We want to regroup up to 4 integers per line, which means they
    165	 * need to be in the same pr_devel() statement
    166	 */
    167	ptr = (int *) buf;
    168	for (i = 0; i * 4 < buf_len; i += 4) {
    169		if ((i + 3) * 4 < buf_len)
    170			pr_devel("%.8x %.8x %.8x %.8x\n", ptr[i], ptr[i + 1],
    171				ptr[i + 2], ptr[i + 3]);
    172		else if ((i + 2) * 4 < buf_len)
    173			pr_devel("%.8x %.8x %.8x\n", ptr[i], ptr[i + 1],
    174				ptr[i + 2]);
    175		else if ((i + 1) * 4 < buf_len)
    176			pr_devel("%.8x %.8x\n", ptr[i], ptr[i + 1]);
    177		else
    178			pr_devel("%.8x\n", ptr[i]);
    179	}
    180#endif /* DEBUG */
    181}
    182
    183/* Find a CXL adapter by it's number and increase it's refcount */
    184struct cxl *get_cxl_adapter(int num)
    185{
    186	struct cxl *adapter;
    187
    188	spin_lock(&adapter_idr_lock);
    189	if ((adapter = idr_find(&cxl_adapter_idr, num)))
    190		get_device(&adapter->dev);
    191	spin_unlock(&adapter_idr_lock);
    192
    193	return adapter;
    194}
    195
    196static int cxl_alloc_adapter_nr(struct cxl *adapter)
    197{
    198	int i;
    199
    200	idr_preload(GFP_KERNEL);
    201	spin_lock(&adapter_idr_lock);
    202	i = idr_alloc(&cxl_adapter_idr, adapter, 0, 0, GFP_NOWAIT);
    203	spin_unlock(&adapter_idr_lock);
    204	idr_preload_end();
    205	if (i < 0)
    206		return i;
    207
    208	adapter->adapter_num = i;
    209
    210	return 0;
    211}
    212
    213void cxl_remove_adapter_nr(struct cxl *adapter)
    214{
    215	idr_remove(&cxl_adapter_idr, adapter->adapter_num);
    216}
    217
    218struct cxl *cxl_alloc_adapter(void)
    219{
    220	struct cxl *adapter;
    221
    222	if (!(adapter = kzalloc(sizeof(struct cxl), GFP_KERNEL)))
    223		return NULL;
    224
    225	spin_lock_init(&adapter->afu_list_lock);
    226
    227	if (cxl_alloc_adapter_nr(adapter))
    228		goto err1;
    229
    230	if (dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))
    231		goto err2;
    232
    233	/* start with context lock taken */
    234	atomic_set(&adapter->contexts_num, -1);
    235
    236	return adapter;
    237err2:
    238	cxl_remove_adapter_nr(adapter);
    239err1:
    240	kfree(adapter);
    241	return NULL;
    242}
    243
    244struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
    245{
    246	struct cxl_afu *afu;
    247
    248	if (!(afu = kzalloc(sizeof(struct cxl_afu), GFP_KERNEL)))
    249		return NULL;
    250
    251	afu->adapter = adapter;
    252	afu->dev.parent = &adapter->dev;
    253	afu->dev.release = cxl_ops->release_afu;
    254	afu->slice = slice;
    255	idr_init(&afu->contexts_idr);
    256	mutex_init(&afu->contexts_lock);
    257	spin_lock_init(&afu->afu_cntl_lock);
    258	atomic_set(&afu->configured_state, -1);
    259	afu->prefault_mode = CXL_PREFAULT_NONE;
    260	afu->irqs_max = afu->adapter->user_irqs;
    261
    262	return afu;
    263}
    264
    265int cxl_afu_select_best_mode(struct cxl_afu *afu)
    266{
    267	if (afu->modes_supported & CXL_MODE_DIRECTED)
    268		return cxl_ops->afu_activate_mode(afu, CXL_MODE_DIRECTED);
    269
    270	if (afu->modes_supported & CXL_MODE_DEDICATED)
    271		return cxl_ops->afu_activate_mode(afu, CXL_MODE_DEDICATED);
    272
    273	dev_warn(&afu->dev, "No supported programming modes available\n");
    274	/* We don't fail this so the user can inspect sysfs */
    275	return 0;
    276}
    277
    278int cxl_adapter_context_get(struct cxl *adapter)
    279{
    280	int rc;
    281
    282	rc = atomic_inc_unless_negative(&adapter->contexts_num);
    283	return rc ? 0 : -EBUSY;
    284}
    285
    286void cxl_adapter_context_put(struct cxl *adapter)
    287{
    288	atomic_dec_if_positive(&adapter->contexts_num);
    289}
    290
    291int cxl_adapter_context_lock(struct cxl *adapter)
    292{
    293	int rc;
    294	/* no active contexts -> contexts_num == 0 */
    295	rc = atomic_cmpxchg(&adapter->contexts_num, 0, -1);
    296	return rc ? -EBUSY : 0;
    297}
    298
    299void cxl_adapter_context_unlock(struct cxl *adapter)
    300{
    301	int val = atomic_cmpxchg(&adapter->contexts_num, -1, 0);
    302
    303	/*
    304	 * contexts lock taken -> contexts_num == -1
    305	 * If not true then show a warning and force reset the lock.
    306	 * This will happen when context_unlock was requested without
    307	 * doing a context_lock.
    308	 */
    309	if (val != -1) {
    310		atomic_set(&adapter->contexts_num, 0);
    311		WARN(1, "Adapter context unlocked with %d active contexts",
    312		     val);
    313	}
    314}
    315
    316static int __init init_cxl(void)
    317{
    318	int rc = 0;
    319
    320	if (!tlbie_capable)
    321		return -EINVAL;
    322
    323	if ((rc = cxl_file_init()))
    324		return rc;
    325
    326	cxl_debugfs_init();
    327
    328	/*
    329	 * we don't register the callback on P9. slb callack is only
    330	 * used for the PSL8 MMU and CX4.
    331	 */
    332	if (cxl_is_power8()) {
    333		rc = register_cxl_calls(&cxl_calls);
    334		if (rc)
    335			goto err;
    336	}
    337
    338	if (cpu_has_feature(CPU_FTR_HVMODE)) {
    339		cxl_ops = &cxl_native_ops;
    340		rc = pci_register_driver(&cxl_pci_driver);
    341	}
    342#ifdef CONFIG_PPC_PSERIES
    343	else {
    344		cxl_ops = &cxl_guest_ops;
    345		rc = platform_driver_register(&cxl_of_driver);
    346	}
    347#endif
    348	if (rc)
    349		goto err1;
    350
    351	return 0;
    352err1:
    353	if (cxl_is_power8())
    354		unregister_cxl_calls(&cxl_calls);
    355err:
    356	cxl_debugfs_exit();
    357	cxl_file_exit();
    358
    359	return rc;
    360}
    361
    362static void exit_cxl(void)
    363{
    364	if (cpu_has_feature(CPU_FTR_HVMODE))
    365		pci_unregister_driver(&cxl_pci_driver);
    366#ifdef CONFIG_PPC_PSERIES
    367	else
    368		platform_driver_unregister(&cxl_of_driver);
    369#endif
    370
    371	cxl_debugfs_exit();
    372	cxl_file_exit();
    373	if (cxl_is_power8())
    374		unregister_cxl_calls(&cxl_calls);
    375	idr_destroy(&cxl_adapter_idr);
    376}
    377
    378module_init(init_cxl);
    379module_exit(exit_cxl);
    380
    381MODULE_DESCRIPTION("IBM Coherent Accelerator");
    382MODULE_AUTHOR("Ian Munsie <imunsie@au1.ibm.com>");
    383MODULE_LICENSE("GPL");