1 /* $NetBSD: drm_pci.c,v 1.6 2014/07/26 07:53:14 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: drm_pci.c,v 1.6 2014/07/26 07:53:14 riastradh Exp $"); 34 35 #include <sys/types.h> 36 #include <sys/errno.h> 37 #include <sys/systm.h> 38 39 #include <dev/pci/pcivar.h> 40 41 #include <drm/drmP.h> 42 43 static int drm_pci_get_irq(struct drm_device *); 44 static int drm_pci_irq_install(struct drm_device *, 45 irqreturn_t (*)(void *), int, const char *, void *, 46 struct drm_bus_irq_cookie **); 47 static void drm_pci_irq_uninstall(struct drm_device *, 48 struct drm_bus_irq_cookie *); 49 static const char * 50 drm_pci_get_name(struct drm_device *); 51 static int drm_pci_set_busid(struct drm_device *, struct drm_master *); 52 static int drm_pci_set_unique(struct drm_device *, struct drm_master *, 53 struct drm_unique *); 54 static int drm_pci_irq_by_busid(struct drm_device *, 55 struct drm_irq_busid *); 56 57 const struct drm_bus drm_pci_bus = { 58 .bus_type = DRIVER_BUS_PCI, 59 .get_irq = drm_pci_get_irq, 60 .irq_install = drm_pci_irq_install, 61 .irq_uninstall = drm_pci_irq_uninstall, 62 .get_name = drm_pci_get_name, 63 .set_busid = drm_pci_set_busid, 64 .set_unique = drm_pci_set_unique, 65 .irq_by_busid = drm_pci_irq_by_busid, 66 }; 67 68 static const struct pci_attach_args * 69 drm_pci_attach_args(struct drm_device *dev) 70 { 71 return &dev->pdev->pd_pa; 72 } 73 74 int 75 drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver __unused) 76 { 77 78 driver->bus = &drm_pci_bus; 79 return 0; 80 } 81 82 void 83 drm_pci_exit(struct drm_driver *driver __unused, 84 struct pci_driver *pdriver __unused) 85 { 86 } 87 88 int 89 drm_pci_attach(device_t self, const struct pci_attach_args *pa, 90 struct pci_dev *pdev, struct drm_driver *driver, unsigned long cookie, 91 struct drm_device **devp) 92 { 93 struct drm_device *dev; 94 unsigned int unit; 95 int ret; 96 97 /* Initialize the Linux PCI device descriptor. */ 98 linux_pci_dev_init(pdev, self, pa, 0); 99 100 /* Create a DRM device. */ 101 dev = drm_dev_alloc(driver, self); 102 if (dev == NULL) { 103 ret = -ENOMEM; 104 goto fail0; 105 } 106 107 dev->pdev = pdev; 108 109 /* XXX Set the power state to D0? */ 110 111 /* Set up the bus space and bus DMA tags. */ 112 dev->bst = pa->pa_memt; 113 /* XXX Let the driver say something about 32-bit vs 64-bit DMA? */ 114 dev->bus_dmat = (pci_dma64_available(pa)? pa->pa_dmat64 : pa->pa_dmat); 115 dev->dmat = dev->bus_dmat; 116 dev->dmat_subregion_p = false; 117 118 /* Find all the memory maps. */ 119 CTASSERT(PCI_NUM_RESOURCES < (SIZE_MAX / sizeof(dev->bus_maps[0]))); 120 dev->bus_maps = kmem_zalloc(PCI_NUM_RESOURCES * 121 sizeof(dev->bus_maps[0]), KM_SLEEP); 122 dev->bus_nmaps = PCI_NUM_RESOURCES; 123 for (unit = 0; unit < PCI_NUM_RESOURCES; unit++) { 124 struct drm_bus_map *const bm = &dev->bus_maps[unit]; 125 const int reg = PCI_BAR(unit); 126 const pcireg_t type = 127 pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg); 128 129 /* Reject non-memory mappings. */ 130 if ((type & PCI_MAPREG_TYPE_MEM) != PCI_MAPREG_TYPE_MEM) { 131 aprint_debug_dev(self, "map %u has non-memory type:" 132 " 0x%"PRIxMAX"\n", unit, (uintmax_t)type); 133 continue; 134 } 135 136 /* Inquire about it. We'll map it in drm_ioremap. */ 137 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type, 138 &bm->bm_base, &bm->bm_size, &bm->bm_flags) != 0) { 139 aprint_debug_dev(self, "map %u failed\n", unit); 140 continue; 141 } 142 143 /* Assume since it is a memory mapping it can be linear. */ 144 bm->bm_flags |= BUS_SPACE_MAP_LINEAR; 145 } 146 147 /* Set up AGP stuff if requested. */ 148 if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { 149 if (drm_pci_device_is_agp(dev)) 150 dev->agp = drm_agp_init(dev); 151 if (dev->agp) 152 dev->agp->agp_mtrr = arch_phys_wc_add(dev->agp->base, 153 dev->agp->agp_info.aki_info.ai_aperture_size); 154 } 155 156 /* Register the DRM device and do driver-specific initialization. */ 157 ret = drm_dev_register(dev, cookie); 158 if (ret) 159 goto fail1; 160 161 /* Success! */ 162 *devp = dev; 163 return 0; 164 165 fail2: __unused 166 drm_dev_unregister(dev); 167 fail1: drm_pci_agp_destroy(dev); 168 dev->bus_nmaps = 0; 169 kmem_free(dev->bus_maps, PCI_NUM_RESOURCES * sizeof(dev->bus_maps[0])); 170 if (dev->dmat_subregion_p) 171 bus_dmatag_destroy(dev->dmat); 172 drm_dev_unref(dev); 173 fail0: return ret; 174 } 175 176 int 177 drm_pci_detach(struct drm_device *dev, int flags __unused) 178 { 179 180 /* Do driver-specific detachment and unregister the device. */ 181 drm_dev_unregister(dev); 182 183 /* Tear down AGP stuff if necessary. */ 184 if (dev->agp) { 185 arch_phys_wc_del(dev->agp->agp_mtrr); 186 drm_agp_clear(dev); 187 kfree(dev->agp); /* XXX Should go in drm_agp_clear... */ 188 dev->agp = NULL; 189 } 190 191 /* Free the record of available bus space mappings. */ 192 dev->bus_nmaps = 0; 193 kmem_free(dev->bus_maps, PCI_NUM_RESOURCES * sizeof(dev->bus_maps[0])); 194 195 /* Tear down bus space and bus DMA tags. */ 196 if (dev->dmat_subregion_p) 197 bus_dmatag_destroy(dev->dmat); 198 199 drm_dev_unref(dev); 200 201 return 0; 202 } 203 204 void 205 drm_pci_agp_destroy(struct drm_device *dev) 206 { 207 208 if (dev->agp) { 209 arch_phys_wc_del(dev->agp->agp_mtrr); 210 drm_agp_clear(dev); 211 kfree(dev->agp); /* XXX Should go in drm_agp_clear... */ 212 dev->agp = NULL; 213 } 214 } 215 216 static int 217 drm_pci_get_irq(struct drm_device *dev) 218 { 219 pci_intr_handle_t ih_pih; 220 int ih_int; 221 222 /* 223 * This is a compile-time assertion that the types match. If 224 * this fails, we have to change a bunch of drm code that uses 225 * int for intr handles. 226 */ 227 KASSERT(&ih_pih != &ih_int); 228 229 if (pci_intr_map(drm_pci_attach_args(dev), &ih_pih)) 230 return -1; /* XXX Hope -1 is an invalid intr handle. */ 231 232 ih_int = ih_pih; 233 return ih_int; 234 } 235 236 static int 237 drm_pci_irq_install(struct drm_device *dev, irqreturn_t (*handler)(void *), 238 int flags, const char *name, void *arg, 239 struct drm_bus_irq_cookie **cookiep) 240 { 241 const struct pci_attach_args *const pa = drm_pci_attach_args(dev); 242 pci_intr_handle_t ih; 243 const char *intrstr; 244 void *ih_cookie; 245 char intrbuf[PCI_INTRSTR_LEN]; 246 247 if (pci_intr_map(pa, &ih)) 248 return -ENOENT; 249 250 intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 251 ih_cookie = pci_intr_establish(pa->pa_pc, ih, IPL_DRM, handler, arg); 252 if (ih_cookie == NULL) { 253 aprint_error_dev(dev->dev, 254 "couldn't establish interrupt at %s (%s)\n", 255 intrstr, name); 256 return -ENOENT; 257 } 258 259 aprint_normal_dev(dev->dev, "interrupting at %s (%s)\n", 260 intrstr, name); 261 *cookiep = (struct drm_bus_irq_cookie *)ih_cookie; 262 return 0; 263 } 264 265 static void 266 drm_pci_irq_uninstall(struct drm_device *dev, 267 struct drm_bus_irq_cookie *cookie) 268 { 269 const struct pci_attach_args *pa = drm_pci_attach_args(dev); 270 271 pci_intr_disestablish(pa->pa_pc, (void *)cookie); 272 } 273 274 static const char * 275 drm_pci_get_name(struct drm_device *dev) 276 { 277 return "pci"; /* XXX PCI bus names? */ 278 } 279 280 static int 281 drm_pci_format_unique(struct drm_device *dev, char *buf, size_t size) 282 { 283 const unsigned int domain = device_unit(device_parent(dev->dev)); 284 const unsigned int bus = dev->pdev->pd_pa.pa_bus; 285 const unsigned int device = dev->pdev->pd_pa.pa_device; 286 const unsigned int function = dev->pdev->pd_pa.pa_function; 287 288 return snprintf(buf, size, "pci:%04x:%02x:%02x.%d", 289 domain, bus, device, function); 290 } 291 292 static int 293 drm_pci_format_devname(struct drm_device *dev, const char *unique, 294 char *buf, size_t size) 295 { 296 297 return snprintf(buf, size, "%s@%s", 298 device_xname(device_parent(dev->dev)), 299 unique); 300 } 301 302 static int 303 drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) 304 { 305 int n; 306 char *buf; 307 308 n = drm_pci_format_unique(dev, NULL, 0); 309 if (n < 0) 310 return -ENOSPC; /* XXX */ 311 if (0xff < n) 312 n = 0xff; 313 314 buf = kzalloc(n + 1, GFP_KERNEL); 315 (void)drm_pci_format_unique(dev, buf, n + 1); 316 317 if (master->unique) 318 kfree(master->unique); 319 master->unique = buf; 320 master->unique_len = n; 321 master->unique_size = n + 1; 322 323 n = drm_pci_format_devname(dev, master->unique, NULL, 0); 324 if (n < 0) 325 return -ENOSPC; /* XXX back out? */ 326 if (0xff < n) 327 n = 0xff; 328 329 buf = kzalloc(n + 1, GFP_KERNEL); 330 (void)drm_pci_format_devname(dev, master->unique, buf, n + 1); 331 332 if (dev->devname) 333 kfree(dev->devname); 334 dev->devname = buf; 335 336 return 0; 337 } 338 339 static int 340 drm_pci_set_unique(struct drm_device *dev, struct drm_master *master, 341 struct drm_unique *unique __unused) 342 { 343 344 /* 345 * XXX This is silly. We're supposed to reject unique names 346 * that don't match the ones we would generate anyway. For 347 * expedience, we'll just generate the one we would and ignore 348 * whatever userland threw at us... 349 */ 350 return drm_pci_set_busid(dev, master); 351 } 352 353 static int 354 drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *busid) 355 { 356 return -ENOSYS; /* XXX */ 357 } 358