1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * DAWR infrastructure |
4 | * |
5 | * Copyright 2019, Michael Neuling, IBM Corporation. |
6 | */ |
7 | |
8 | #include <linux/types.h> |
9 | #include <linux/export.h> |
10 | #include <linux/fs.h> |
11 | #include <linux/debugfs.h> |
12 | #include <asm/machdep.h> |
13 | #include <asm/hvcall.h> |
14 | #include <asm/firmware.h> |
15 | |
16 | bool dawr_force_enable; |
17 | EXPORT_SYMBOL_GPL(dawr_force_enable); |
18 | |
19 | int set_dawr(int nr, struct arch_hw_breakpoint *brk) |
20 | { |
21 | unsigned long dawr, dawrx, mrd; |
22 | |
23 | dawr = brk->address; |
24 | |
25 | dawrx = (brk->type & (HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)) |
26 | << (63 - 58); |
27 | dawrx |= ((brk->type & (HW_BRK_TYPE_TRANSLATE)) >> 2) << (63 - 59); |
28 | dawrx |= (brk->type & (HW_BRK_TYPE_PRIV_ALL)) >> 3; |
29 | /* |
30 | * DAWR length is stored in field MDR bits 48:53. Matches range in |
31 | * doublewords (64 bits) biased by -1 eg. 0b000000=1DW and |
32 | * 0b111111=64DW. |
33 | * brk->hw_len is in bytes. |
34 | * This aligns up to double word size, shifts and does the bias. |
35 | */ |
36 | mrd = ((brk->hw_len + 7) >> 3) - 1; |
37 | dawrx |= (mrd & 0x3f) << (63 - 53); |
38 | |
39 | if (ppc_md.set_dawr) |
40 | return ppc_md.set_dawr(nr, dawr, dawrx); |
41 | |
42 | if (nr == 0) { |
43 | mtspr(SPRN_DAWR0, dawr); |
44 | mtspr(SPRN_DAWRX0, dawrx); |
45 | } else { |
46 | mtspr(SPRN_DAWR1, dawr); |
47 | mtspr(SPRN_DAWRX1, dawrx); |
48 | } |
49 | |
50 | return 0; |
51 | } |
52 | |
53 | static void disable_dawrs_cb(void *info) |
54 | { |
55 | struct arch_hw_breakpoint null_brk = {0}; |
56 | int i; |
57 | |
58 | for (i = 0; i < nr_wp_slots(); i++) |
59 | set_dawr(nr: i, brk: &null_brk); |
60 | } |
61 | |
62 | static ssize_t dawr_write_file_bool(struct file *file, |
63 | const char __user *user_buf, |
64 | size_t count, loff_t *ppos) |
65 | { |
66 | struct arch_hw_breakpoint null_brk = {0}; |
67 | size_t rc; |
68 | |
69 | /* Send error to user if they hypervisor won't allow us to write DAWR */ |
70 | if (!dawr_force_enable && |
71 | firmware_has_feature(FW_FEATURE_LPAR) && |
72 | set_dawr(nr: 0, brk: &null_brk) != H_SUCCESS) |
73 | return -ENODEV; |
74 | |
75 | rc = debugfs_write_file_bool(file, user_buf, count, ppos); |
76 | if (rc) |
77 | return rc; |
78 | |
79 | /* If we are clearing, make sure all CPUs have the DAWR cleared */ |
80 | if (!dawr_force_enable) |
81 | smp_call_function(func: disable_dawrs_cb, NULL, wait: 0); |
82 | |
83 | return rc; |
84 | } |
85 | |
86 | static const struct file_operations dawr_enable_fops = { |
87 | .read = debugfs_read_file_bool, |
88 | .write = dawr_write_file_bool, |
89 | .open = simple_open, |
90 | .llseek = default_llseek, |
91 | }; |
92 | |
93 | static int __init dawr_force_setup(void) |
94 | { |
95 | if (cpu_has_feature(CPU_FTR_DAWR)) { |
96 | /* Don't setup sysfs file for user control on P8 */ |
97 | dawr_force_enable = true; |
98 | return 0; |
99 | } |
100 | |
101 | if (PVR_VER(mfspr(SPRN_PVR)) == PVR_POWER9) { |
102 | /* Turn DAWR off by default, but allow admin to turn it on */ |
103 | debugfs_create_file_unsafe(name: "dawr_enable_dangerous" , mode: 0600, |
104 | parent: arch_debugfs_dir, |
105 | data: &dawr_force_enable, |
106 | fops: &dawr_enable_fops); |
107 | } |
108 | return 0; |
109 | } |
110 | arch_initcall(dawr_force_setup); |
111 | |