1 /*- 2 * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * Simple driver for PCI VGA display devices. Drivers such as agp(4) and 35 * drm(4) should attach as children of this device. 36 * 37 * XXX: The vgapci name is a hack until we somehow merge the isa vga driver 38 * in or rename it. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/bus.h> 43 #include <sys/kernel.h> 44 #include <sys/module.h> 45 #include <sys/rman.h> 46 #include <sys/systm.h> 47 48 #include <dev/pci/pcireg.h> 49 #include <dev/pci/pcivar.h> 50 51 struct vga_resource { 52 struct resource *vr_res; 53 int vr_refs; 54 }; 55 56 struct vga_pci_softc { 57 device_t vga_msi_child; /* Child driver using MSI. */ 58 struct vga_resource vga_res[PCIR_MAX_BAR_0 + 1]; 59 }; 60 61 static int 62 vga_pci_probe(device_t dev) 63 { 64 65 switch (pci_get_class(dev)) { 66 case PCIC_DISPLAY: 67 break; 68 case PCIC_OLD: 69 if (pci_get_subclass(dev) != PCIS_OLD_VGA) 70 return (ENXIO); 71 break; 72 default: 73 return (ENXIO); 74 } 75 device_set_desc(dev, "VGA-compatible display"); 76 return (BUS_PROBE_GENERIC); 77 } 78 79 static int 80 vga_pci_attach(device_t dev) 81 { 82 83 bus_generic_probe(dev); 84 85 /* Always create a drm child for now to make it easier on drm. */ 86 device_add_child(dev, "drm", -1); 87 bus_generic_attach(dev); 88 return (0); 89 } 90 91 static int 92 vga_pci_suspend(device_t dev) 93 { 94 95 return (bus_generic_suspend(dev)); 96 } 97 98 static int 99 vga_pci_resume(device_t dev) 100 { 101 102 return (bus_generic_resume(dev)); 103 } 104 105 /* Bus interface. */ 106 107 static int 108 vga_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 109 { 110 111 return (BUS_READ_IVAR(device_get_parent(dev), dev, which, result)); 112 } 113 114 static int 115 vga_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 116 { 117 118 return (EINVAL); 119 } 120 121 static int 122 vga_pci_setup_intr(device_t dev, device_t child, struct resource *irq, 123 int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, 124 void **cookiep) 125 { 126 return (BUS_SETUP_INTR(device_get_parent(dev), dev, irq, flags, 127 filter, intr, arg, cookiep)); 128 } 129 130 static int 131 vga_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, 132 void *cookie) 133 { 134 return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, irq, cookie)); 135 } 136 137 static struct resource * 138 vga_pci_alloc_resource(device_t dev, device_t child, int type, int *rid, 139 u_long start, u_long end, u_long count, u_int flags) 140 { 141 struct vga_pci_softc *sc; 142 int bar; 143 144 switch (type) { 145 case SYS_RES_MEMORY: 146 case SYS_RES_IOPORT: 147 /* 148 * For BARs, we cache the resource so that we only allocate it 149 * from the PCI bus once. 150 */ 151 bar = PCI_RID2BAR(*rid); 152 if (bar < 0 || bar > PCIR_MAX_BAR_0) 153 return (NULL); 154 sc = device_get_softc(dev); 155 if (sc->vga_res[bar].vr_res == NULL) 156 sc->vga_res[bar].vr_res = bus_alloc_resource(dev, type, 157 rid, start, end, count, flags); 158 if (sc->vga_res[bar].vr_res != NULL) 159 sc->vga_res[bar].vr_refs++; 160 return (sc->vga_res[bar].vr_res); 161 } 162 return (bus_alloc_resource(dev, type, rid, start, end, count, flags)); 163 } 164 165 static int 166 vga_pci_release_resource(device_t dev, device_t child, int type, int rid, 167 struct resource *r) 168 { 169 struct vga_pci_softc *sc; 170 int bar, error; 171 172 switch (type) { 173 case SYS_RES_MEMORY: 174 case SYS_RES_IOPORT: 175 /* 176 * For BARs, we release the resource from the PCI bus 177 * when the last child reference goes away. 178 */ 179 bar = PCI_RID2BAR(rid); 180 if (bar < 0 || bar > PCIR_MAX_BAR_0) 181 return (EINVAL); 182 sc = device_get_softc(dev); 183 if (sc->vga_res[bar].vr_res == NULL) 184 return (EINVAL); 185 KASSERT(sc->vga_res[bar].vr_res == r, 186 ("vga_pci resource mismatch")); 187 if (sc->vga_res[bar].vr_refs > 1) { 188 sc->vga_res[bar].vr_refs--; 189 return (0); 190 } 191 KASSERT(sc->vga_res[bar].vr_refs > 0, 192 ("vga_pci resource reference count underflow")); 193 error = bus_release_resource(dev, type, rid, r); 194 if (error == 0) { 195 sc->vga_res[bar].vr_res = NULL; 196 sc->vga_res[bar].vr_refs = 0; 197 } 198 return (error); 199 } 200 201 return (bus_release_resource(dev, type, rid, r)); 202 } 203 204 /* PCI interface. */ 205 206 static uint32_t 207 vga_pci_read_config(device_t dev, device_t child, int reg, int width) 208 { 209 210 return (pci_read_config(dev, reg, width)); 211 } 212 213 static void 214 vga_pci_write_config(device_t dev, device_t child, int reg, 215 uint32_t val, int width) 216 { 217 218 pci_write_config(dev, reg, val, width); 219 } 220 221 static int 222 vga_pci_enable_busmaster(device_t dev, device_t child) 223 { 224 225 device_printf(dev, "child %s requested pci_enable_busmaster\n", 226 device_get_nameunit(child)); 227 return (pci_enable_busmaster(dev)); 228 } 229 230 static int 231 vga_pci_disable_busmaster(device_t dev, device_t child) 232 { 233 234 device_printf(dev, "child %s requested pci_disable_busmaster\n", 235 device_get_nameunit(child)); 236 return (pci_disable_busmaster(dev)); 237 } 238 239 static int 240 vga_pci_enable_io(device_t dev, device_t child, int space) 241 { 242 243 device_printf(dev, "child %s requested pci_enable_io\n", 244 device_get_nameunit(child)); 245 return (pci_enable_io(dev, space)); 246 } 247 248 static int 249 vga_pci_disable_io(device_t dev, device_t child, int space) 250 { 251 252 device_printf(dev, "child %s requested pci_disable_io\n", 253 device_get_nameunit(child)); 254 return (pci_disable_io(dev, space)); 255 } 256 257 static int 258 vga_pci_get_vpd_ident(device_t dev, device_t child, const char **identptr) 259 { 260 261 return (pci_get_vpd_ident(dev, identptr)); 262 } 263 264 static int 265 vga_pci_get_vpd_readonly(device_t dev, device_t child, const char *kw, 266 const char **vptr) 267 { 268 269 return (pci_get_vpd_readonly(dev, kw, vptr)); 270 } 271 272 static int 273 vga_pci_set_powerstate(device_t dev, device_t child, int state) 274 { 275 276 device_printf(dev, "child %s requested pci_set_powerstate\n", 277 device_get_nameunit(child)); 278 return (pci_set_powerstate(dev, state)); 279 } 280 281 static int 282 vga_pci_get_powerstate(device_t dev, device_t child) 283 { 284 285 device_printf(dev, "child %s requested pci_get_powerstate\n", 286 device_get_nameunit(child)); 287 return (pci_get_powerstate(dev)); 288 } 289 290 static int 291 vga_pci_assign_interrupt(device_t dev, device_t child) 292 { 293 294 device_printf(dev, "child %s requested pci_assign_interrupt\n", 295 device_get_nameunit(child)); 296 return (PCI_ASSIGN_INTERRUPT(device_get_parent(dev), dev)); 297 } 298 299 static int 300 vga_pci_find_extcap(device_t dev, device_t child, int capability, 301 int *capreg) 302 { 303 304 return (pci_find_extcap(dev, capability, capreg)); 305 } 306 307 static int 308 vga_pci_alloc_msi(device_t dev, device_t child, int *count) 309 { 310 struct vga_pci_softc *sc; 311 int error; 312 313 sc = device_get_softc(dev); 314 if (sc->vga_msi_child != NULL) 315 return (EBUSY); 316 error = pci_alloc_msi(dev, count); 317 if (error == 0) 318 sc->vga_msi_child = child; 319 return (error); 320 } 321 322 static int 323 vga_pci_alloc_msix(device_t dev, device_t child, int *count) 324 { 325 struct vga_pci_softc *sc; 326 int error; 327 328 sc = device_get_softc(dev); 329 if (sc->vga_msi_child != NULL) 330 return (EBUSY); 331 error = pci_alloc_msix(dev, count); 332 if (error == 0) 333 sc->vga_msi_child = child; 334 return (error); 335 } 336 337 static int 338 vga_pci_remap_msix(device_t dev, device_t child, int count, 339 const u_int *vectors) 340 { 341 struct vga_pci_softc *sc; 342 343 sc = device_get_softc(dev); 344 if (sc->vga_msi_child != child) 345 return (ENXIO); 346 return (pci_remap_msix(dev, count, vectors)); 347 } 348 349 static int 350 vga_pci_release_msi(device_t dev, device_t child) 351 { 352 struct vga_pci_softc *sc; 353 int error; 354 355 sc = device_get_softc(dev); 356 if (sc->vga_msi_child != child) 357 return (ENXIO); 358 error = pci_release_msi(dev); 359 if (error == 0) 360 sc->vga_msi_child = NULL; 361 return (error); 362 } 363 364 static int 365 vga_pci_msi_count(device_t dev, device_t child) 366 { 367 368 return (pci_msi_count(dev)); 369 } 370 371 static int 372 vga_pci_msix_count(device_t dev, device_t child) 373 { 374 375 return (pci_msix_count(dev)); 376 } 377 378 static device_method_t vga_pci_methods[] = { 379 /* Device interface */ 380 DEVMETHOD(device_probe, vga_pci_probe), 381 DEVMETHOD(device_attach, vga_pci_attach), 382 DEVMETHOD(device_shutdown, bus_generic_shutdown), 383 DEVMETHOD(device_suspend, vga_pci_suspend), 384 DEVMETHOD(device_resume, vga_pci_resume), 385 386 /* Bus interface */ 387 DEVMETHOD(bus_read_ivar, vga_pci_read_ivar), 388 DEVMETHOD(bus_write_ivar, vga_pci_write_ivar), 389 DEVMETHOD(bus_setup_intr, vga_pci_setup_intr), 390 DEVMETHOD(bus_teardown_intr, vga_pci_teardown_intr), 391 392 DEVMETHOD(bus_alloc_resource, vga_pci_alloc_resource), 393 DEVMETHOD(bus_release_resource, vga_pci_release_resource), 394 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 395 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 396 397 /* PCI interface */ 398 DEVMETHOD(pci_read_config, vga_pci_read_config), 399 DEVMETHOD(pci_write_config, vga_pci_write_config), 400 DEVMETHOD(pci_enable_busmaster, vga_pci_enable_busmaster), 401 DEVMETHOD(pci_disable_busmaster, vga_pci_disable_busmaster), 402 DEVMETHOD(pci_enable_io, vga_pci_enable_io), 403 DEVMETHOD(pci_disable_io, vga_pci_disable_io), 404 DEVMETHOD(pci_get_vpd_ident, vga_pci_get_vpd_ident), 405 DEVMETHOD(pci_get_vpd_readonly, vga_pci_get_vpd_readonly), 406 DEVMETHOD(pci_get_powerstate, vga_pci_get_powerstate), 407 DEVMETHOD(pci_set_powerstate, vga_pci_set_powerstate), 408 DEVMETHOD(pci_assign_interrupt, vga_pci_assign_interrupt), 409 DEVMETHOD(pci_find_extcap, vga_pci_find_extcap), 410 DEVMETHOD(pci_alloc_msi, vga_pci_alloc_msi), 411 DEVMETHOD(pci_alloc_msix, vga_pci_alloc_msix), 412 DEVMETHOD(pci_remap_msix, vga_pci_remap_msix), 413 DEVMETHOD(pci_release_msi, vga_pci_release_msi), 414 DEVMETHOD(pci_msi_count, vga_pci_msi_count), 415 DEVMETHOD(pci_msix_count, vga_pci_msix_count), 416 417 { 0, 0 } 418 }; 419 420 static driver_t vga_pci_driver = { 421 "vgapci", 422 vga_pci_methods, 423 sizeof(struct vga_pci_softc), 424 }; 425 426 static devclass_t vga_devclass; 427 428 DRIVER_MODULE(vgapci, pci, vga_pci_driver, vga_devclass, 0, 0); 429