1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // VCPU stall detector. 4 // Copyright (C) Google, 2022 5 6 #include <linux/cpu.h> 7 #include <linux/init.h> 8 #include <linux/io.h> 9 #include <linux/kernel.h> 10 11 #include <linux/device.h> 12 #include <linux/interrupt.h> 13 #include <linux/module.h> 14 #include <linux/nmi.h> 15 #include <linux/of.h> 16 #include <linux/of_device.h> 17 #include <linux/param.h> 18 #include <linux/percpu.h> 19 #include <linux/platform_device.h> 20 #include <linux/slab.h> 21 22 #define VCPU_STALL_REG_STATUS (0x00) 23 #define VCPU_STALL_REG_LOAD_CNT (0x04) 24 #define VCPU_STALL_REG_CURRENT_CNT (0x08) 25 #define VCPU_STALL_REG_CLOCK_FREQ_HZ (0x0C) 26 #define VCPU_STALL_REG_LEN (0x10) 27 28 #define VCPU_STALL_DEFAULT_CLOCK_HZ (10) 29 #define VCPU_STALL_MAX_CLOCK_HZ (100) 30 #define VCPU_STALL_DEFAULT_TIMEOUT_SEC (8) 31 #define VCPU_STALL_MAX_TIMEOUT_SEC (600) 32 33 struct vcpu_stall_detect_config { 34 u32 clock_freq_hz; 35 u32 stall_timeout_sec; 36 37 void __iomem *membase; 38 struct platform_device *dev; 39 enum cpuhp_state hp_online; 40 }; 41 42 struct vcpu_stall_priv { 43 struct hrtimer vcpu_hrtimer; 44 bool is_initialized; 45 }; 46 47 /* The vcpu stall configuration structure which applies to all the CPUs */ 48 static struct vcpu_stall_detect_config vcpu_stall_config; 49 50 #define vcpu_stall_reg_write(vcpu, reg, value) \ 51 writel_relaxed((value), \ 52 (void __iomem *)(vcpu_stall_config.membase + \ 53 (vcpu) * VCPU_STALL_REG_LEN + (reg))) 54 55 56 static struct vcpu_stall_priv __percpu *vcpu_stall_detectors; 57 58 static enum hrtimer_restart 59 vcpu_stall_detect_timer_fn(struct hrtimer *hrtimer) 60 { 61 u32 ticks, ping_timeout_ms; 62 63 /* Reload the stall detector counter register every 64 * `ping_timeout_ms` to prevent the virtual device 65 * from decrementing it to 0. The virtual device decrements this 66 * register at 'clock_freq_hz' frequency. 67 */ 68 ticks = vcpu_stall_config.clock_freq_hz * 69 vcpu_stall_config.stall_timeout_sec; 70 vcpu_stall_reg_write(smp_processor_id(), 71 VCPU_STALL_REG_LOAD_CNT, ticks); 72 73 ping_timeout_ms = vcpu_stall_config.stall_timeout_sec * 74 MSEC_PER_SEC / 2; 75 hrtimer_forward_now(hrtimer, 76 ms_to_ktime(ping_timeout_ms)); 77 78 return HRTIMER_RESTART; 79 } 80 81 static int start_stall_detector_cpu(unsigned int cpu) 82 { 83 u32 ticks, ping_timeout_ms; 84 struct vcpu_stall_priv *vcpu_stall_detector = 85 this_cpu_ptr(vcpu_stall_detectors); 86 struct hrtimer *vcpu_hrtimer = &vcpu_stall_detector->vcpu_hrtimer; 87 88 vcpu_stall_reg_write(cpu, VCPU_STALL_REG_CLOCK_FREQ_HZ, 89 vcpu_stall_config.clock_freq_hz); 90 91 /* Compute the number of ticks required for the stall detector 92 * counter register based on the internal clock frequency and the 93 * timeout value given from the device tree. 94 */ 95 ticks = vcpu_stall_config.clock_freq_hz * 96 vcpu_stall_config.stall_timeout_sec; 97 vcpu_stall_reg_write(cpu, VCPU_STALL_REG_LOAD_CNT, ticks); 98 99 /* Enable the internal clock and start the stall detector */ 100 vcpu_stall_reg_write(cpu, VCPU_STALL_REG_STATUS, 1); 101 102 /* Pet the stall detector at half of its expiration timeout 103 * to prevent spurious resets. 104 */ 105 ping_timeout_ms = vcpu_stall_config.stall_timeout_sec * 106 MSEC_PER_SEC / 2; 107 108 hrtimer_init(vcpu_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 109 vcpu_hrtimer->function = vcpu_stall_detect_timer_fn; 110 vcpu_stall_detector->is_initialized = true; 111 112 hrtimer_start(vcpu_hrtimer, ms_to_ktime(ping_timeout_ms), 113 HRTIMER_MODE_REL_PINNED); 114 115 return 0; 116 } 117 118 static int stop_stall_detector_cpu(unsigned int cpu) 119 { 120 struct vcpu_stall_priv *vcpu_stall_detector = 121 per_cpu_ptr(vcpu_stall_detectors, cpu); 122 123 if (!vcpu_stall_detector->is_initialized) 124 return 0; 125 126 /* Disable the stall detector for the current CPU */ 127 hrtimer_cancel(&vcpu_stall_detector->vcpu_hrtimer); 128 vcpu_stall_reg_write(cpu, VCPU_STALL_REG_STATUS, 0); 129 vcpu_stall_detector->is_initialized = false; 130 131 return 0; 132 } 133 134 static int vcpu_stall_detect_probe(struct platform_device *pdev) 135 { 136 int ret; 137 struct resource *r; 138 void __iomem *membase; 139 u32 clock_freq_hz = VCPU_STALL_DEFAULT_CLOCK_HZ; 140 u32 stall_timeout_sec = VCPU_STALL_DEFAULT_TIMEOUT_SEC; 141 struct device_node *np = pdev->dev.of_node; 142 143 vcpu_stall_detectors = devm_alloc_percpu(&pdev->dev, 144 typeof(struct vcpu_stall_priv)); 145 if (!vcpu_stall_detectors) 146 return -ENOMEM; 147 148 membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r); 149 if (IS_ERR(membase)) { 150 dev_err(&pdev->dev, "Failed to get memory resource\n"); 151 return PTR_ERR(membase); 152 } 153 154 if (!of_property_read_u32(np, "clock-frequency", &clock_freq_hz)) { 155 if (!(clock_freq_hz > 0 && 156 clock_freq_hz < VCPU_STALL_MAX_CLOCK_HZ)) { 157 dev_warn(&pdev->dev, "clk out of range\n"); 158 clock_freq_hz = VCPU_STALL_DEFAULT_CLOCK_HZ; 159 } 160 } 161 162 if (!of_property_read_u32(np, "timeout-sec", &stall_timeout_sec)) { 163 if (!(stall_timeout_sec > 0 && 164 stall_timeout_sec < VCPU_STALL_MAX_TIMEOUT_SEC)) { 165 dev_warn(&pdev->dev, "stall timeout out of range\n"); 166 stall_timeout_sec = VCPU_STALL_DEFAULT_TIMEOUT_SEC; 167 } 168 } 169 170 vcpu_stall_config = (struct vcpu_stall_detect_config) { 171 .membase = membase, 172 .clock_freq_hz = clock_freq_hz, 173 .stall_timeout_sec = stall_timeout_sec 174 }; 175 176 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, 177 "virt/vcpu_stall_detector:online", 178 start_stall_detector_cpu, 179 stop_stall_detector_cpu); 180 if (ret < 0) { 181 dev_err(&pdev->dev, "failed to install cpu hotplug"); 182 goto err; 183 } 184 185 vcpu_stall_config.hp_online = ret; 186 return 0; 187 err: 188 return ret; 189 } 190 191 static int vcpu_stall_detect_remove(struct platform_device *pdev) 192 { 193 int cpu; 194 195 cpuhp_remove_state(vcpu_stall_config.hp_online); 196 197 for_each_possible_cpu(cpu) 198 stop_stall_detector_cpu(cpu); 199 200 return 0; 201 } 202 203 static const struct of_device_id vcpu_stall_detect_of_match[] = { 204 { .compatible = "qemu,vcpu-stall-detector", }, 205 {} 206 }; 207 208 MODULE_DEVICE_TABLE(of, vcpu_stall_detect_of_match); 209 210 static struct platform_driver vcpu_stall_detect_driver = { 211 .probe = vcpu_stall_detect_probe, 212 .remove = vcpu_stall_detect_remove, 213 .driver = { 214 .name = KBUILD_MODNAME, 215 .of_match_table = vcpu_stall_detect_of_match, 216 }, 217 }; 218 219 module_platform_driver(vcpu_stall_detect_driver); 220 221 MODULE_LICENSE("GPL"); 222 MODULE_AUTHOR("Sebastian Ene <sebastianene@google.com>"); 223 MODULE_DESCRIPTION("VCPU stall detector"); 224