1 /* $NetBSD: drm_pci.c,v 1.33 2020/02/14 04:29:19 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.33 2020/02/14 04:29:19 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 #include <drm/drm_legacy.h> 43 44 struct drm_bus_irq_cookie { 45 pci_intr_handle_t *intr_handles; 46 void *ih_cookie; 47 }; 48 49 static const struct pci_attach_args * 50 drm_pci_attach_args(struct drm_device *dev) 51 { 52 return &dev->pdev->pd_pa; 53 } 54 55 int 56 drm_pci_attach(device_t self, const struct pci_attach_args *pa, 57 struct pci_dev *pdev, struct drm_driver *driver, unsigned long cookie, 58 struct drm_device **devp) 59 { 60 struct drm_device *dev; 61 unsigned int unit; 62 int ret; 63 64 /* Ensure the drm agp hooks are initialized. */ 65 /* XXX errno NetBSD->Linux */ 66 ret = -drm_guarantee_initialized(); 67 if (ret) 68 goto fail0; 69 70 /* Create a DRM device. */ 71 dev = drm_dev_alloc(driver, self); 72 if (dev == NULL) { 73 ret = -ENOMEM; 74 goto fail0; 75 } 76 77 dev->pdev = pdev; 78 pdev->pd_drm_dev = dev; /* XXX Nouveau kludge. */ 79 80 /* XXX Set the power state to D0? */ 81 82 /* Set up the bus space and bus DMA tags. */ 83 dev->bst = pa->pa_memt; 84 dev->bus_dmat = (pci_dma64_available(pa)? pa->pa_dmat64 : pa->pa_dmat); 85 dev->bus_dmat32 = pa->pa_dmat; 86 dev->dmat = dev->bus_dmat; 87 dev->dmat_subregion_p = false; 88 dev->dmat_subregion_min = 0; 89 dev->dmat_subregion_max = __type_max(bus_addr_t); 90 91 /* Find all the memory maps. */ 92 CTASSERT(PCI_NUM_RESOURCES < (SIZE_MAX / sizeof(dev->bus_maps[0]))); 93 dev->bus_maps = kmem_zalloc(PCI_NUM_RESOURCES * 94 sizeof(dev->bus_maps[0]), KM_SLEEP); 95 dev->bus_nmaps = PCI_NUM_RESOURCES; 96 for (unit = 0; unit < PCI_NUM_RESOURCES; unit++) { 97 struct drm_bus_map *const bm = &dev->bus_maps[unit]; 98 const int reg = PCI_BAR(unit); 99 const pcireg_t type = 100 pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg); 101 102 /* Reject non-memory mappings. */ 103 if ((type & PCI_MAPREG_TYPE_MEM) != PCI_MAPREG_TYPE_MEM) { 104 aprint_debug_dev(self, "map %u has non-memory type:" 105 " 0x%"PRIxMAX"\n", unit, (uintmax_t)type); 106 continue; 107 } 108 109 /* 110 * If it's a 64-bit mapping, don't interpret the second 111 * half of it as another BAR in the next iteration of 112 * the loop -- move on to the next unit. 113 */ 114 if (PCI_MAPREG_MEM_TYPE(type) == PCI_MAPREG_MEM_TYPE_64BIT) 115 unit++; 116 117 /* Inquire about it. We'll map it in drm_legacy_ioremap. */ 118 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type, 119 &bm->bm_base, &bm->bm_size, &bm->bm_flags) != 0) { 120 aprint_debug_dev(self, "map %u failed\n", unit); 121 continue; 122 } 123 124 /* Assume since it is a memory mapping it can be linear. */ 125 bm->bm_flags |= BUS_SPACE_MAP_LINEAR; 126 } 127 128 /* Set up AGP stuff if requested. */ 129 if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { 130 if (drm_pci_device_is_agp(dev)) 131 dev->agp = drm_agp_init(dev); 132 if (dev->agp) 133 dev->agp->agp_mtrr = arch_phys_wc_add(dev->agp->base, 134 dev->agp->agp_info.aki_info.ai_aperture_size); 135 } 136 137 /* Register the DRM device and do driver-specific initialization. */ 138 ret = drm_dev_register(dev, cookie); 139 if (ret) 140 goto fail1; 141 142 /* Success! */ 143 *devp = dev; 144 return 0; 145 146 fail2: __unused 147 drm_dev_unregister(dev); 148 fail1: drm_pci_agp_destroy(dev); 149 dev->bus_nmaps = 0; 150 kmem_free(dev->bus_maps, PCI_NUM_RESOURCES * sizeof(dev->bus_maps[0])); 151 if (dev->dmat_subregion_p) { 152 bus_dmatag_destroy(dev->dmat); 153 } 154 drm_dev_unref(dev); 155 fail0: return ret; 156 } 157 158 int 159 drm_pci_detach(struct drm_device *dev, int flags __unused) 160 { 161 162 /* Do driver-specific detachment and unregister the device. */ 163 drm_dev_unregister(dev); 164 165 /* Tear down AGP stuff if necessary. */ 166 drm_pci_agp_destroy(dev); 167 168 /* Free the record of available bus space mappings. */ 169 dev->bus_nmaps = 0; 170 kmem_free(dev->bus_maps, PCI_NUM_RESOURCES * sizeof(dev->bus_maps[0])); 171 172 /* Tear down bus space and bus DMA tags. */ 173 if (dev->dmat_subregion_p) { 174 bus_dmatag_destroy(dev->dmat); 175 } 176 177 drm_dev_unref(dev); 178 179 return 0; 180 } 181 182 void 183 drm_pci_agp_destroy(struct drm_device *dev) 184 { 185 186 if (dev->agp) { 187 arch_phys_wc_del(dev->agp->agp_mtrr); 188 drm_agp_fini(dev); 189 KASSERT(dev->agp == NULL); 190 } 191 } 192 193 int 194 drm_pci_request_irq(struct drm_device *dev, int flags) 195 { 196 const char *const name = device_xname(dev->dev); 197 int (*const handler)(void *) = dev->driver->irq_handler; 198 const struct pci_attach_args *const pa = drm_pci_attach_args(dev); 199 const char *intrstr; 200 char intrbuf[PCI_INTRSTR_LEN]; 201 struct drm_bus_irq_cookie *irq_cookie; 202 203 irq_cookie = kmem_alloc(sizeof(*irq_cookie), KM_SLEEP); 204 205 if (dev->pdev->msi_enabled) { 206 if (dev->pdev->pd_intr_handles == NULL) { 207 if (pci_msi_alloc_exact(pa, &irq_cookie->intr_handles, 208 1)) { 209 aprint_error_dev(dev->dev, 210 "couldn't allocate MSI (%s)\n", name); 211 goto error; 212 } 213 } else { 214 irq_cookie->intr_handles = dev->pdev->pd_intr_handles; 215 dev->pdev->pd_intr_handles = NULL; 216 } 217 } else { 218 if (pci_intx_alloc(pa, &irq_cookie->intr_handles)) { 219 aprint_error_dev(dev->dev, 220 "couldn't allocate INTx interrupt (%s)\n", name); 221 goto error; 222 } 223 } 224 225 intrstr = pci_intr_string(pa->pa_pc, irq_cookie->intr_handles[0], 226 intrbuf, sizeof(intrbuf)); 227 irq_cookie->ih_cookie = pci_intr_establish_xname(pa->pa_pc, 228 irq_cookie->intr_handles[0], IPL_DRM, handler, dev, name); 229 if (irq_cookie->ih_cookie == NULL) { 230 aprint_error_dev(dev->dev, 231 "couldn't establish interrupt at %s (%s)\n", intrstr, name); 232 pci_intr_release(pa->pa_pc, irq_cookie->intr_handles, 1); 233 goto error; 234 } 235 236 aprint_normal_dev(dev->dev, "interrupting at %s (%s)\n", intrstr, name); 237 dev->irq_cookie = irq_cookie; 238 return 0; 239 240 error: 241 kmem_free(irq_cookie, sizeof(*irq_cookie)); 242 return -ENOENT; 243 } 244 245 void 246 drm_pci_free_irq(struct drm_device *dev) 247 { 248 struct drm_bus_irq_cookie *const cookie = dev->irq_cookie; 249 const struct pci_attach_args *pa = drm_pci_attach_args(dev); 250 251 pci_intr_disestablish(pa->pa_pc, cookie->ih_cookie); 252 pci_intr_release(pa->pa_pc, cookie->intr_handles, 1); 253 kmem_free(cookie, sizeof(*cookie)); 254 dev->irq_cookie = NULL; 255 } 256 257 int 258 drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) 259 { 260 const struct pci_attach_args *const pa = &dev->pdev->pd_pa; 261 262 master->unique = kasprintf(GFP_KERNEL, "pci:%04x:%02x:%02x.%d", 263 device_unit(device_parent(dev->dev)), 264 pa->pa_bus, pa->pa_device, pa->pa_function); 265 if (master->unique == NULL) 266 return -ENOMEM; 267 master->unique_len = strlen(master->unique); 268 269 return 0; 270 } 271 272 int 273 drm_pci_set_unique(struct drm_device *dev, struct drm_master *master, 274 struct drm_unique *unique) 275 { 276 char kbuf[64], ubuf[64]; 277 int ret; 278 279 /* Reject excessively long unique strings. */ 280 if (unique->unique_len > sizeof(ubuf) - 1) 281 return -EINVAL; 282 283 /* Copy in the alleged unique string, NUL-terminated. */ 284 ret = -copyin(unique->unique, ubuf, unique->unique_len); 285 if (ret) 286 return ret; 287 ubuf[unique->unique_len] = '\0'; 288 289 /* Make sure it matches what we expect. */ 290 snprintf(kbuf, sizeof kbuf, "PCI:%d:%ld:%ld", dev->pdev->bus->number, 291 (long)PCI_SLOT(dev->pdev->devfn), 292 (long)PCI_FUNC(dev->pdev->devfn)); 293 if (strncmp(kbuf, ubuf, sizeof(kbuf)) != 0) 294 return -EINVAL; 295 296 /* Remember it. */ 297 master->unique = kstrdup(ubuf, GFP_KERNEL); 298 master->unique_len = strlen(master->unique); 299 300 /* Success! */ 301 return 0; 302 } 303 304 int 305 drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *speed_mask) 306 { 307 308 return -ENOSYS; 309 } 310