1 /* 2 * Copyright (c) 2015 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Imre Vadász <imre@vdsz.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "opt_acpi.h" 36 #include <sys/param.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/bus.h> 40 #include <sys/rman.h> 41 #include <dev/acpica/acpi_pvpanic/panic_notifier.h> 42 43 #include "acpi.h" 44 45 #include <dev/acpica/acpivar.h> 46 47 #define PVPANIC_GUESTPANIC (1 << 0) 48 49 ACPI_MODULE_NAME("pvpanic") 50 51 struct acpi_pvpanic_softc { 52 device_t dev; 53 ACPI_HANDLE handle; 54 int pvpanic_port_rid; 55 struct resource *pvpanic_port_res; 56 bus_space_tag_t pvpanic_iot; 57 bus_space_handle_t pvpanic_ioh; 58 struct panicerinfo pvpanic_info; 59 }; 60 61 static int acpi_pvpanic_probe(device_t dev); 62 static int acpi_pvpanic_attach(device_t dev); 63 static int acpi_pvpanic_detach(device_t dev); 64 static void acpi_pvpanic_panic(void *arg); 65 66 static device_method_t acpi_pvpanic_methods[] = { 67 DEVMETHOD(device_probe, acpi_pvpanic_probe), 68 DEVMETHOD(device_attach, acpi_pvpanic_attach), 69 DEVMETHOD(device_detach, acpi_pvpanic_detach), 70 71 DEVMETHOD_END 72 }; 73 74 static driver_t acpi_pvpanic_driver = { 75 "acpi_pvpanic", 76 acpi_pvpanic_methods, 77 sizeof(struct acpi_pvpanic_softc), 78 }; 79 80 static devclass_t acpi_pvpanic_devclass; 81 DRIVER_MODULE(acpi_pvpanic, acpi, acpi_pvpanic_driver, acpi_pvpanic_devclass, 82 NULL, NULL); 83 MODULE_DEPEND(acpi_pvpanic, acpi, 1, 1, 1); 84 MODULE_VERSION(acpi_pvpanic, 1); 85 86 static int 87 acpi_pvpanic_probe(device_t dev) 88 { 89 static char *pvpanic_ids[] = { "QEMU0001", NULL }; 90 91 if (acpi_disabled("pvpanic") || 92 ACPI_ID_PROBE(device_get_parent(dev), dev, pvpanic_ids) == NULL || 93 device_get_unit(dev) != 0) 94 return (ENXIO); 95 96 device_set_desc(dev, "Qemu pvpanic device"); 97 return (0); 98 } 99 100 static int 101 acpi_pvpanic_attach(device_t dev) 102 { 103 struct acpi_pvpanic_softc *sc; 104 uint8_t val; 105 106 sc = device_get_softc(dev); 107 sc->dev = dev; 108 sc->handle = acpi_get_handle(dev); 109 110 sc->pvpanic_port_rid = 0; 111 sc->pvpanic_port_res = bus_alloc_resource_any(sc->dev, SYS_RES_IOPORT, 112 &sc->pvpanic_port_rid, RF_ACTIVE); 113 if (sc->pvpanic_port_res == NULL) { 114 device_printf(dev, "can't allocate pvpanic port\n"); 115 return ENXIO; 116 } 117 sc->pvpanic_iot = rman_get_bustag(sc->pvpanic_port_res); 118 sc->pvpanic_ioh = rman_get_bushandle(sc->pvpanic_port_res); 119 120 /* Check for guest panic notification support */ 121 val = bus_space_read_1(sc->pvpanic_iot, sc->pvpanic_ioh, 0); 122 if (!(val & PVPANIC_GUESTPANIC)) { 123 device_printf(dev, "No PVPANIC_GUESTPANIC support\n"); 124 goto fail; 125 } 126 127 device_printf(dev, "Registering panic callback\n"); 128 sc->pvpanic_info.notifier = acpi_pvpanic_panic; 129 sc->pvpanic_info.arg = sc; 130 if (set_panic_notifier(&sc->pvpanic_info) != 0) { 131 device_printf(dev, "Failed to register panic notifier\n"); 132 goto fail; 133 } 134 return (0); 135 136 fail: 137 bus_release_resource(dev, SYS_RES_IOPORT, 138 sc->pvpanic_port_rid, sc->pvpanic_port_res); 139 return ENXIO; 140 } 141 142 static int 143 acpi_pvpanic_detach(device_t dev) 144 { 145 struct acpi_pvpanic_softc *sc = device_get_softc(dev); 146 147 set_panic_notifier(NULL); 148 149 bus_release_resource(dev, SYS_RES_IOPORT, 150 sc->pvpanic_port_rid, sc->pvpanic_port_res); 151 152 return (0); 153 } 154 155 static void 156 acpi_pvpanic_panic(void *arg) 157 { 158 struct acpi_pvpanic_softc *sc = (struct acpi_pvpanic_softc *)arg; 159 160 bus_space_write_1(sc->pvpanic_iot, sc->pvpanic_ioh, 0, 161 PVPANIC_GUESTPANIC); 162 } 163