Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * DAWR infrastructure
0004  *
0005  * Copyright 2019, Michael Neuling, IBM Corporation.
0006  */
0007 
0008 #include <linux/types.h>
0009 #include <linux/export.h>
0010 #include <linux/fs.h>
0011 #include <linux/debugfs.h>
0012 #include <asm/machdep.h>
0013 #include <asm/hvcall.h>
0014 #include <asm/firmware.h>
0015 
0016 bool dawr_force_enable;
0017 EXPORT_SYMBOL_GPL(dawr_force_enable);
0018 
0019 int set_dawr(int nr, struct arch_hw_breakpoint *brk)
0020 {
0021     unsigned long dawr, dawrx, mrd;
0022 
0023     dawr = brk->address;
0024 
0025     dawrx  = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE))
0026         << (63 - 58);
0027     dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) << (63 - 59);
0028     dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) >> 3;
0029     /*
0030      * DAWR length is stored in field MDR bits 48:53.  Matches range in
0031      * doublewords (64 bits) biased by -1 eg. 0b000000=1DW and
0032      * 0b111111=64DW.
0033      * brk->hw_len is in bytes.
0034      * This aligns up to double word size, shifts and does the bias.
0035      */
0036     mrd = ((brk->hw_len + 7) >> 3) - 1;
0037     dawrx |= (mrd & 0x3f) << (63 - 53);
0038 
0039     if (ppc_md.set_dawr)
0040         return ppc_md.set_dawr(nr, dawr, dawrx);
0041 
0042     if (nr == 0) {
0043         mtspr(SPRN_DAWR0, dawr);
0044         mtspr(SPRN_DAWRX0, dawrx);
0045     } else {
0046         mtspr(SPRN_DAWR1, dawr);
0047         mtspr(SPRN_DAWRX1, dawrx);
0048     }
0049 
0050     return 0;
0051 }
0052 
0053 static void disable_dawrs_cb(void *info)
0054 {
0055     struct arch_hw_breakpoint null_brk = {0};
0056     int i;
0057 
0058     for (i = 0; i < nr_wp_slots(); i++)
0059         set_dawr(i, &null_brk);
0060 }
0061 
0062 static ssize_t dawr_write_file_bool(struct file *file,
0063                     const char __user *user_buf,
0064                     size_t count, loff_t *ppos)
0065 {
0066     struct arch_hw_breakpoint null_brk = {0};
0067     size_t rc;
0068 
0069     /* Send error to user if they hypervisor won't allow us to write DAWR */
0070     if (!dawr_force_enable &&
0071         firmware_has_feature(FW_FEATURE_LPAR) &&
0072         set_dawr(0, &null_brk) != H_SUCCESS)
0073         return -ENODEV;
0074 
0075     rc = debugfs_write_file_bool(file, user_buf, count, ppos);
0076     if (rc)
0077         return rc;
0078 
0079     /* If we are clearing, make sure all CPUs have the DAWR cleared */
0080     if (!dawr_force_enable)
0081         smp_call_function(disable_dawrs_cb, NULL, 0);
0082 
0083     return rc;
0084 }
0085 
0086 static const struct file_operations dawr_enable_fops = {
0087     .read =     debugfs_read_file_bool,
0088     .write =    dawr_write_file_bool,
0089     .open =     simple_open,
0090     .llseek =   default_llseek,
0091 };
0092 
0093 static int __init dawr_force_setup(void)
0094 {
0095     if (cpu_has_feature(CPU_FTR_DAWR)) {
0096         /* Don't setup sysfs file for user control on P8 */
0097         dawr_force_enable = true;
0098         return 0;
0099     }
0100 
0101     if (PVR_VER(mfspr(SPRN_PVR)) == PVR_POWER9) {
0102         /* Turn DAWR off by default, but allow admin to turn it on */
0103         debugfs_create_file_unsafe("dawr_enable_dangerous", 0600,
0104                        arch_debugfs_dir,
0105                        &dawr_force_enable,
0106                        &dawr_enable_fops);
0107     }
0108     return 0;
0109 }
0110 arch_initcall(dawr_force_setup);