1 /* $NetBSD: drm_pci.c,v 1.3 2014/03/29 19:54:46 christos 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.3 2014/03/29 19:54:46 christos 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 static int drm_pci_agp_init(struct drm_device *); 57 58 const struct drm_bus drm_pci_bus = { 59 .bus_type = DRIVER_BUS_PCI, 60 .get_irq = drm_pci_get_irq, 61 .irq_install = drm_pci_irq_install, 62 .irq_uninstall = drm_pci_irq_uninstall, 63 .get_name = drm_pci_get_name, 64 .set_busid = drm_pci_set_busid, 65 .set_unique = drm_pci_set_unique, 66 .irq_by_busid = drm_pci_irq_by_busid, 67 .agp_init = drm_pci_agp_init, 68 }; 69 70 static const struct pci_attach_args * 71 drm_pci_attach_args(struct drm_device *dev) 72 { 73 return &dev->pdev->pd_pa; 74 } 75 76 int 77 drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver __unused) 78 { 79 80 driver->bus = &drm_pci_bus; 81 return 0; 82 } 83 84 void 85 drm_pci_exit(struct drm_driver *driver __unused, 86 struct pci_driver *pdriver __unused) 87 { 88 } 89 90 /* XXX Should go elsewhere. */ 91 #define PCI_NMAPREGS ((PCI_MAPREG_END - PCI_MAPREG_START) / 4) 92 93 void 94 drm_pci_attach(device_t self, const struct pci_attach_args *pa, 95 struct pci_dev *pdev, struct drm_device *dev) 96 { 97 unsigned int unit; 98 99 linux_pci_dev_init(pdev, self, pa, 0); 100 101 dev->pdev = pdev; 102 dev->pci_vendor = pdev->vendor; 103 dev->pci_device = pdev->device; 104 105 /* XXX Set the power state to D0? */ 106 107 dev->bst = pa->pa_memt; 108 /* XXX Let the driver say something about 32-bit vs 64-bit DMA? */ 109 dev->bus_dmat = (pci_dma64_available(pa)? pa->pa_dmat64 : pa->pa_dmat); 110 dev->dmat = dev->bus_dmat; 111 dev->dmat_subregion_p = false; 112 113 CTASSERT(PCI_NMAPREGS < (SIZE_MAX / sizeof(dev->bus_maps[0]))); 114 dev->bus_nmaps = PCI_NMAPREGS; 115 dev->bus_maps = kmem_zalloc((PCI_NMAPREGS * sizeof(dev->bus_maps[0])), 116 KM_SLEEP); 117 for (unit = 0; unit < dev->bus_nmaps; unit++) { 118 struct drm_bus_map *const bm = &dev->bus_maps[unit]; 119 const int reg = PCI_BAR(unit); 120 const pcireg_t type = 121 pci_mapreg_type(pa->pa_pc, pa->pa_tag, reg); 122 123 /* Reject non-memory mappings. */ 124 if ((type & PCI_MAPREG_TYPE_MEM) != PCI_MAPREG_TYPE_MEM) { 125 aprint_debug_dev(self, "map %u has non-memory type:" 126 " 0x%"PRIxMAX"\n", unit, (uintmax_t)type); 127 continue; 128 } 129 130 /* Inquire about it. We'll map it in drm_ioremap. */ 131 if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, reg, type, 132 &bm->bm_base, &bm->bm_size, &bm->bm_flags) != 0) { 133 aprint_debug_dev(self, "map %u failed\n", unit); 134 continue; 135 } 136 137 aprint_debug_dev(self, "map %u at %"PRIxMAX" size %"PRIxMAX 138 " flags 0x%"PRIxMAX"\n", 139 unit, (uintmax_t)bm->bm_base, (uintmax_t)bm->bm_size, 140 (uintmax_t)bm->bm_flags); 141 142 /* Assume since it is a memory mapping it can be linear. */ 143 bm->bm_flags |= BUS_SPACE_MAP_LINEAR; 144 } 145 146 /* All `agp' maps are just initialized to zero. */ 147 CTASSERT(PCI_NMAPREGS < (SIZE_MAX / sizeof(dev->agp_maps[0]))); 148 dev->agp_nmaps = PCI_NMAPREGS; 149 dev->agp_maps = kmem_zalloc((PCI_NMAPREGS * sizeof(dev->agp_maps[0])), 150 KM_SLEEP); 151 } 152 153 int 154 drm_pci_detach(struct drm_device *dev __unused, int flags __unused) 155 { 156 157 kmem_free(dev->bus_maps, (PCI_NMAPREGS * sizeof(dev->bus_maps[0]))); 158 kmem_free(dev->agp_maps, (PCI_NMAPREGS * sizeof(dev->agp_maps[0]))); 159 160 /* 161 * XXX This is the wrong place! Should be a routine in 162 * drm_memory.c. 163 */ 164 if (dev->dmat_subregion_p) 165 bus_dmatag_destroy(dev->dmat); 166 167 /* XXX Disestablish irqs or anything? */ 168 return 0; 169 } 170 171 static int 172 drm_pci_get_irq(struct drm_device *dev) 173 { 174 pci_intr_handle_t ih_pih; 175 int ih_int; 176 177 /* 178 * This is a compile-time assertion that the types match. If 179 * this fails, we have to change a bunch of drm code that uses 180 * int for intr handles. 181 */ 182 KASSERT(&ih_pih != &ih_int); 183 184 if (pci_intr_map(drm_pci_attach_args(dev), &ih_pih)) 185 return -1; /* XXX Hope -1 is an invalid intr handle. */ 186 187 ih_int = ih_pih; 188 return ih_int; 189 } 190 191 static int 192 drm_pci_irq_install(struct drm_device *dev, irqreturn_t (*handler)(void *), 193 int flags, const char *name, void *arg, 194 struct drm_bus_irq_cookie **cookiep) 195 { 196 const struct pci_attach_args *const pa = drm_pci_attach_args(dev); 197 pci_intr_handle_t ih; 198 const char *intrstr; 199 void *ih_cookie; 200 char intrbuf[PCI_INTRSTR_LEN]; 201 202 if (pci_intr_map(pa, &ih)) 203 return -ENOENT; 204 205 intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); 206 ih_cookie = pci_intr_establish(pa->pa_pc, ih, IPL_DRM, handler, arg); 207 if (ih_cookie == NULL) { 208 aprint_error_dev(dev->dev, 209 "couldn't establish interrupt at %s (%s)\n", 210 intrstr, name); 211 return -ENOENT; 212 } 213 214 aprint_normal_dev(dev->dev, "interrupting at %s (%s)\n", 215 intrstr, name); 216 *cookiep = (struct drm_bus_irq_cookie *)ih_cookie; 217 return 0; 218 } 219 220 static void 221 drm_pci_irq_uninstall(struct drm_device *dev, 222 struct drm_bus_irq_cookie *cookie) 223 { 224 const struct pci_attach_args *pa = drm_pci_attach_args(dev); 225 226 pci_intr_disestablish(pa->pa_pc, (void *)cookie); 227 } 228 229 static const char * 230 drm_pci_get_name(struct drm_device *dev) 231 { 232 return "pci"; /* XXX PCI bus names? */ 233 } 234 235 static int 236 drm_pci_format_unique(struct drm_device *dev, char *buf, size_t size) 237 { 238 const unsigned int domain = 0; /* XXX PCI domains? */ 239 const unsigned int bus = dev->pdev->pd_pa.pa_bus; 240 const unsigned int device = dev->pdev->pd_pa.pa_device; 241 const unsigned int function = dev->pdev->pd_pa.pa_function; 242 243 return snprintf(buf, size, "pci:%04x:%02x:%02x.%d", 244 domain, bus, device, function); 245 } 246 247 static int 248 drm_pci_format_devname(struct drm_device *dev, const char *unique, 249 char *buf, size_t size) 250 { 251 252 return snprintf(buf, size, "%s@%s", 253 device_xname(device_parent(dev->dev)), 254 unique); 255 } 256 257 static int 258 drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) 259 { 260 int n; 261 char *buf; 262 263 n = drm_pci_format_unique(dev, NULL, 0); 264 if (n < 0) 265 return -ENOSPC; /* XXX */ 266 if (0xff < n) 267 n = 0xff; 268 269 buf = kzalloc(n + 1, GFP_KERNEL); 270 (void)drm_pci_format_unique(dev, buf, n + 1); 271 272 if (master->unique) 273 kfree(master->unique); 274 master->unique = buf; 275 master->unique_len = n; 276 master->unique_size = n + 1; 277 278 n = drm_pci_format_devname(dev, master->unique, NULL, 0); 279 if (n < 0) 280 return -ENOSPC; /* XXX back out? */ 281 if (0xff < n) 282 n = 0xff; 283 284 buf = kzalloc(n + 1, GFP_KERNEL); 285 (void)drm_pci_format_devname(dev, master->unique, buf, n + 1); 286 287 if (dev->devname) 288 kfree(dev->devname); 289 dev->devname = buf; 290 291 return 0; 292 } 293 294 static int 295 drm_pci_set_unique(struct drm_device *dev, struct drm_master *master, 296 struct drm_unique *unique __unused) 297 { 298 299 /* 300 * XXX This is silly. We're supposed to reject unique names 301 * that don't match the ones we would generate anyway. For 302 * expedience, we'll just generate the one we would and ignore 303 * whatever userland threw at us... 304 */ 305 return drm_pci_set_busid(dev, master); 306 } 307 308 static int 309 drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *busid) 310 { 311 return -ENOSYS; /* XXX */ 312 } 313 314 static int 315 drm_pci_agp_init(struct drm_device *dev) 316 { 317 return 0; /* XXX */ 318 } 319