1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Pvpanic MMIO Device Support 4 * 5 * Copyright (C) 2013 Fujitsu. 6 * Copyright (C) 2018 ZTE. 7 * Copyright (C) 2021 Oracle. 8 */ 9 10 #include <linux/io.h> 11 #include <linux/kernel.h> 12 #include <linux/kexec.h> 13 #include <linux/mod_devicetable.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 #include <linux/types.h> 17 18 #include <uapi/misc/pvpanic.h> 19 20 #include "pvpanic.h" 21 22 MODULE_AUTHOR("Hu Tao <hutao@cn.fujitsu.com>"); 23 MODULE_DESCRIPTION("pvpanic-mmio device driver"); 24 MODULE_LICENSE("GPL"); 25 26 static void __iomem *base; 27 static unsigned int capability = PVPANIC_PANICKED | PVPANIC_CRASH_LOADED; 28 static unsigned int events; 29 30 static ssize_t capability_show(struct device *dev, 31 struct device_attribute *attr, char *buf) 32 { 33 return sysfs_emit(buf, "%x\n", capability); 34 } 35 static DEVICE_ATTR_RO(capability); 36 37 static ssize_t events_show(struct device *dev, struct device_attribute *attr, char *buf) 38 { 39 return sysfs_emit(buf, "%x\n", events); 40 } 41 42 static ssize_t events_store(struct device *dev, struct device_attribute *attr, 43 const char *buf, size_t count) 44 { 45 unsigned int tmp; 46 int err; 47 48 err = kstrtouint(buf, 16, &tmp); 49 if (err) 50 return err; 51 52 if ((tmp & capability) != tmp) 53 return -EINVAL; 54 55 events = tmp; 56 57 pvpanic_set_events(events); 58 59 return count; 60 61 } 62 static DEVICE_ATTR_RW(events); 63 64 static struct attribute *pvpanic_mmio_dev_attrs[] = { 65 &dev_attr_capability.attr, 66 &dev_attr_events.attr, 67 NULL 68 }; 69 ATTRIBUTE_GROUPS(pvpanic_mmio_dev); 70 71 static int pvpanic_mmio_probe(struct platform_device *pdev) 72 { 73 struct device *dev = &pdev->dev; 74 struct resource *res; 75 76 res = platform_get_mem_or_io(pdev, 0); 77 if (!res) 78 return -EINVAL; 79 80 switch (resource_type(res)) { 81 case IORESOURCE_IO: 82 base = devm_ioport_map(dev, res->start, resource_size(res)); 83 if (!base) 84 return -ENOMEM; 85 break; 86 case IORESOURCE_MEM: 87 base = devm_ioremap_resource(dev, res); 88 if (IS_ERR(base)) 89 return PTR_ERR(base); 90 break; 91 default: 92 return -EINVAL; 93 } 94 95 /* initlize capability by RDPT */ 96 capability &= ioread8(base); 97 events = capability; 98 99 pvpanic_probe(base, capability); 100 101 return 0; 102 } 103 104 static int pvpanic_mmio_remove(struct platform_device *pdev) 105 { 106 107 pvpanic_remove(); 108 109 return 0; 110 } 111 112 static const struct of_device_id pvpanic_mmio_match[] = { 113 { .compatible = "qemu,pvpanic-mmio", }, 114 {} 115 }; 116 MODULE_DEVICE_TABLE(of, pvpanic_mmio_match); 117 118 static const struct acpi_device_id pvpanic_device_ids[] = { 119 { "QEMU0001", 0 }, 120 { "", 0 } 121 }; 122 MODULE_DEVICE_TABLE(acpi, pvpanic_device_ids); 123 124 static struct platform_driver pvpanic_mmio_driver = { 125 .driver = { 126 .name = "pvpanic-mmio", 127 .of_match_table = pvpanic_mmio_match, 128 .acpi_match_table = pvpanic_device_ids, 129 .dev_groups = pvpanic_mmio_dev_groups, 130 }, 131 .probe = pvpanic_mmio_probe, 132 .remove = pvpanic_mmio_remove, 133 }; 134 module_platform_driver(pvpanic_mmio_driver); 135