1*592ffb21SWarner Losh /* drm_pci.h -- PCI DMA memory management wrappers for DRM -*- linux-c -*- */ 2*592ffb21SWarner Losh /** 3*592ffb21SWarner Losh * \file drm_pci.c 4*592ffb21SWarner Losh * \brief Functions and ioctls to manage PCI memory 5*592ffb21SWarner Losh * 6*592ffb21SWarner Losh * \warning These interfaces aren't stable yet. 7*592ffb21SWarner Losh * 8*592ffb21SWarner Losh * \todo Implement the remaining ioctl's for the PCI pools. 9*592ffb21SWarner Losh * \todo The wrappers here are so thin that they would be better off inlined.. 10*592ffb21SWarner Losh * 11*592ffb21SWarner Losh * \author José Fonseca <jrfonseca@tungstengraphics.com> 12*592ffb21SWarner Losh * \author Leif Delgass <ldelgass@retinalburn.net> 13*592ffb21SWarner Losh */ 14*592ffb21SWarner Losh 15*592ffb21SWarner Losh /* 16*592ffb21SWarner Losh * Copyright 2003 José Fonseca. 17*592ffb21SWarner Losh * Copyright 2003 Leif Delgass. 18*592ffb21SWarner Losh * All Rights Reserved. 19*592ffb21SWarner Losh * 20*592ffb21SWarner Losh * Permission is hereby granted, free of charge, to any person obtaining a 21*592ffb21SWarner Losh * copy of this software and associated documentation files (the "Software"), 22*592ffb21SWarner Losh * to deal in the Software without restriction, including without limitation 23*592ffb21SWarner Losh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 24*592ffb21SWarner Losh * and/or sell copies of the Software, and to permit persons to whom the 25*592ffb21SWarner Losh * Software is furnished to do so, subject to the following conditions: 26*592ffb21SWarner Losh * 27*592ffb21SWarner Losh * The above copyright notice and this permission notice (including the next 28*592ffb21SWarner Losh * paragraph) shall be included in all copies or substantial portions of the 29*592ffb21SWarner Losh * Software. 30*592ffb21SWarner Losh * 31*592ffb21SWarner Losh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32*592ffb21SWarner Losh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33*592ffb21SWarner Losh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34*592ffb21SWarner Losh * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 35*592ffb21SWarner Losh * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 36*592ffb21SWarner Losh * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37*592ffb21SWarner Losh */ 38*592ffb21SWarner Losh 39*592ffb21SWarner Losh #include <sys/cdefs.h> 40*592ffb21SWarner Losh __FBSDID("$FreeBSD$"); 41*592ffb21SWarner Losh 42*592ffb21SWarner Losh #include <dev/drm2/drmP.h> 43*592ffb21SWarner Losh 44*592ffb21SWarner Losh static int drm_msi = 1; /* Enable by default. */ 45*592ffb21SWarner Losh SYSCTL_NODE(_hw, OID_AUTO, drm, CTLFLAG_RW, NULL, "DRM device"); 46*592ffb21SWarner Losh SYSCTL_INT(_hw_drm, OID_AUTO, msi, CTLFLAG_RDTUN, &drm_msi, 1, 47*592ffb21SWarner Losh "Enable MSI interrupts for drm devices"); 48*592ffb21SWarner Losh 49*592ffb21SWarner Losh /**********************************************************************/ 50*592ffb21SWarner Losh /** \name PCI memory */ 51*592ffb21SWarner Losh /*@{*/ 52*592ffb21SWarner Losh 53*592ffb21SWarner Losh static void 54*592ffb21SWarner Losh drm_pci_busdma_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 55*592ffb21SWarner Losh { 56*592ffb21SWarner Losh drm_dma_handle_t *dmah = arg; 57*592ffb21SWarner Losh 58*592ffb21SWarner Losh if (error != 0) 59*592ffb21SWarner Losh return; 60*592ffb21SWarner Losh 61*592ffb21SWarner Losh KASSERT(nsegs == 1, ("drm_pci_busdma_callback: bad dma segment count")); 62*592ffb21SWarner Losh dmah->busaddr = segs[0].ds_addr; 63*592ffb21SWarner Losh } 64*592ffb21SWarner Losh 65*592ffb21SWarner Losh /** 66*592ffb21SWarner Losh * \brief Allocate a PCI consistent memory block, for DMA. 67*592ffb21SWarner Losh */ 68*592ffb21SWarner Losh drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, 69*592ffb21SWarner Losh size_t align, dma_addr_t maxaddr) 70*592ffb21SWarner Losh { 71*592ffb21SWarner Losh drm_dma_handle_t *dmah; 72*592ffb21SWarner Losh int ret; 73*592ffb21SWarner Losh 74*592ffb21SWarner Losh /* Need power-of-two alignment, so fail the allocation if it isn't. */ 75*592ffb21SWarner Losh if ((align & (align - 1)) != 0) { 76*592ffb21SWarner Losh DRM_ERROR("drm_pci_alloc with non-power-of-two alignment %d\n", 77*592ffb21SWarner Losh (int)align); 78*592ffb21SWarner Losh return NULL; 79*592ffb21SWarner Losh } 80*592ffb21SWarner Losh 81*592ffb21SWarner Losh dmah = malloc(sizeof(drm_dma_handle_t), DRM_MEM_DMA, M_ZERO | M_NOWAIT); 82*592ffb21SWarner Losh if (dmah == NULL) 83*592ffb21SWarner Losh return NULL; 84*592ffb21SWarner Losh 85*592ffb21SWarner Losh /* Make sure we aren't holding mutexes here */ 86*592ffb21SWarner Losh mtx_assert(&dev->dma_lock, MA_NOTOWNED); 87*592ffb21SWarner Losh if (mtx_owned(&dev->dma_lock)) 88*592ffb21SWarner Losh DRM_ERROR("called while holding dma_lock\n"); 89*592ffb21SWarner Losh 90*592ffb21SWarner Losh ret = bus_dma_tag_create( 91*592ffb21SWarner Losh bus_get_dma_tag(dev->dev), /* parent */ 92*592ffb21SWarner Losh align, 0, /* align, boundary */ 93*592ffb21SWarner Losh maxaddr, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ 94*592ffb21SWarner Losh NULL, NULL, /* filtfunc, filtfuncargs */ 95*592ffb21SWarner Losh size, 1, size, /* maxsize, nsegs, maxsegsize */ 96*592ffb21SWarner Losh 0, NULL, NULL, /* flags, lockfunc, lockfuncargs */ 97*592ffb21SWarner Losh &dmah->tag); 98*592ffb21SWarner Losh if (ret != 0) { 99*592ffb21SWarner Losh free(dmah, DRM_MEM_DMA); 100*592ffb21SWarner Losh return NULL; 101*592ffb21SWarner Losh } 102*592ffb21SWarner Losh 103*592ffb21SWarner Losh ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, 104*592ffb21SWarner Losh BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &dmah->map); 105*592ffb21SWarner Losh if (ret != 0) { 106*592ffb21SWarner Losh bus_dma_tag_destroy(dmah->tag); 107*592ffb21SWarner Losh free(dmah, DRM_MEM_DMA); 108*592ffb21SWarner Losh return NULL; 109*592ffb21SWarner Losh } 110*592ffb21SWarner Losh 111*592ffb21SWarner Losh ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, size, 112*592ffb21SWarner Losh drm_pci_busdma_callback, dmah, BUS_DMA_NOWAIT); 113*592ffb21SWarner Losh if (ret != 0) { 114*592ffb21SWarner Losh bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 115*592ffb21SWarner Losh bus_dma_tag_destroy(dmah->tag); 116*592ffb21SWarner Losh free(dmah, DRM_MEM_DMA); 117*592ffb21SWarner Losh return NULL; 118*592ffb21SWarner Losh } 119*592ffb21SWarner Losh 120*592ffb21SWarner Losh return dmah; 121*592ffb21SWarner Losh } 122*592ffb21SWarner Losh 123*592ffb21SWarner Losh EXPORT_SYMBOL(drm_pci_alloc); 124*592ffb21SWarner Losh 125*592ffb21SWarner Losh /** 126*592ffb21SWarner Losh * \brief Free a PCI consistent memory block without freeing its descriptor. 127*592ffb21SWarner Losh * 128*592ffb21SWarner Losh * This function is for internal use in the Linux-specific DRM core code. 129*592ffb21SWarner Losh */ 130*592ffb21SWarner Losh void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) 131*592ffb21SWarner Losh { 132*592ffb21SWarner Losh if (dmah == NULL) 133*592ffb21SWarner Losh return; 134*592ffb21SWarner Losh 135*592ffb21SWarner Losh bus_dmamap_unload(dmah->tag, dmah->map); 136*592ffb21SWarner Losh bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); 137*592ffb21SWarner Losh bus_dma_tag_destroy(dmah->tag); 138*592ffb21SWarner Losh } 139*592ffb21SWarner Losh 140*592ffb21SWarner Losh /** 141*592ffb21SWarner Losh * \brief Free a PCI consistent memory block 142*592ffb21SWarner Losh */ 143*592ffb21SWarner Losh void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) 144*592ffb21SWarner Losh { 145*592ffb21SWarner Losh __drm_pci_free(dev, dmah); 146*592ffb21SWarner Losh free(dmah, DRM_MEM_DMA); 147*592ffb21SWarner Losh } 148*592ffb21SWarner Losh 149*592ffb21SWarner Losh EXPORT_SYMBOL(drm_pci_free); 150*592ffb21SWarner Losh 151*592ffb21SWarner Losh static int drm_get_pci_domain(struct drm_device *dev) 152*592ffb21SWarner Losh { 153*592ffb21SWarner Losh return dev->pci_domain; 154*592ffb21SWarner Losh } 155*592ffb21SWarner Losh 156*592ffb21SWarner Losh static int drm_pci_get_irq(struct drm_device *dev) 157*592ffb21SWarner Losh { 158*592ffb21SWarner Losh 159*592ffb21SWarner Losh if (dev->irqr) 160*592ffb21SWarner Losh return (dev->irq); 161*592ffb21SWarner Losh 162*592ffb21SWarner Losh dev->irqr = bus_alloc_resource_any(dev->dev, SYS_RES_IRQ, 163*592ffb21SWarner Losh &dev->irqrid, RF_SHAREABLE); 164*592ffb21SWarner Losh if (!dev->irqr) { 165*592ffb21SWarner Losh dev_err(dev->dev, "Failed to allocate IRQ\n"); 166*592ffb21SWarner Losh return (0); 167*592ffb21SWarner Losh } 168*592ffb21SWarner Losh 169*592ffb21SWarner Losh dev->irq = (int) rman_get_start(dev->irqr); 170*592ffb21SWarner Losh 171*592ffb21SWarner Losh return (dev->irq); 172*592ffb21SWarner Losh } 173*592ffb21SWarner Losh 174*592ffb21SWarner Losh static void drm_pci_free_irq(struct drm_device *dev) 175*592ffb21SWarner Losh { 176*592ffb21SWarner Losh if (dev->irqr == NULL) 177*592ffb21SWarner Losh return; 178*592ffb21SWarner Losh 179*592ffb21SWarner Losh bus_release_resource(dev->dev, SYS_RES_IRQ, 180*592ffb21SWarner Losh dev->irqrid, dev->irqr); 181*592ffb21SWarner Losh 182*592ffb21SWarner Losh dev->irqr = NULL; 183*592ffb21SWarner Losh dev->irq = 0; 184*592ffb21SWarner Losh } 185*592ffb21SWarner Losh 186*592ffb21SWarner Losh static const char *drm_pci_get_name(struct drm_device *dev) 187*592ffb21SWarner Losh { 188*592ffb21SWarner Losh return dev->driver->name; 189*592ffb21SWarner Losh } 190*592ffb21SWarner Losh 191*592ffb21SWarner Losh int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) 192*592ffb21SWarner Losh { 193*592ffb21SWarner Losh int len, ret; 194*592ffb21SWarner Losh master->unique_len = 40; 195*592ffb21SWarner Losh master->unique_size = master->unique_len; 196*592ffb21SWarner Losh master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_NOWAIT); 197*592ffb21SWarner Losh if (master->unique == NULL) 198*592ffb21SWarner Losh return -ENOMEM; 199*592ffb21SWarner Losh 200*592ffb21SWarner Losh 201*592ffb21SWarner Losh len = snprintf(master->unique, master->unique_len, 202*592ffb21SWarner Losh "pci:%04x:%02x:%02x.%d", 203*592ffb21SWarner Losh dev->pci_domain, 204*592ffb21SWarner Losh dev->pci_bus, 205*592ffb21SWarner Losh dev->pci_slot, 206*592ffb21SWarner Losh dev->pci_func); 207*592ffb21SWarner Losh 208*592ffb21SWarner Losh if (len >= master->unique_len) { 209*592ffb21SWarner Losh DRM_ERROR("buffer overflow"); 210*592ffb21SWarner Losh ret = -EINVAL; 211*592ffb21SWarner Losh goto err; 212*592ffb21SWarner Losh } else 213*592ffb21SWarner Losh master->unique_len = len; 214*592ffb21SWarner Losh 215*592ffb21SWarner Losh return 0; 216*592ffb21SWarner Losh err: 217*592ffb21SWarner Losh return ret; 218*592ffb21SWarner Losh } 219*592ffb21SWarner Losh 220*592ffb21SWarner Losh int drm_pci_set_unique(struct drm_device *dev, 221*592ffb21SWarner Losh struct drm_master *master, 222*592ffb21SWarner Losh struct drm_unique *u) 223*592ffb21SWarner Losh { 224*592ffb21SWarner Losh int domain, bus, slot, func, ret; 225*592ffb21SWarner Losh 226*592ffb21SWarner Losh master->unique_len = u->unique_len; 227*592ffb21SWarner Losh master->unique_size = u->unique_len + 1; 228*592ffb21SWarner Losh master->unique = malloc(master->unique_size, DRM_MEM_DRIVER, M_WAITOK); 229*592ffb21SWarner Losh if (!master->unique) { 230*592ffb21SWarner Losh ret = -ENOMEM; 231*592ffb21SWarner Losh goto err; 232*592ffb21SWarner Losh } 233*592ffb21SWarner Losh 234*592ffb21SWarner Losh if (copy_from_user(master->unique, u->unique, master->unique_len)) { 235*592ffb21SWarner Losh ret = -EFAULT; 236*592ffb21SWarner Losh goto err; 237*592ffb21SWarner Losh } 238*592ffb21SWarner Losh 239*592ffb21SWarner Losh master->unique[master->unique_len] = '\0'; 240*592ffb21SWarner Losh 241*592ffb21SWarner Losh /* Return error if the busid submitted doesn't match the device's actual 242*592ffb21SWarner Losh * busid. 243*592ffb21SWarner Losh */ 244*592ffb21SWarner Losh ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); 245*592ffb21SWarner Losh if (ret != 3) { 246*592ffb21SWarner Losh ret = -EINVAL; 247*592ffb21SWarner Losh goto err; 248*592ffb21SWarner Losh } 249*592ffb21SWarner Losh 250*592ffb21SWarner Losh domain = bus >> 8; 251*592ffb21SWarner Losh bus &= 0xff; 252*592ffb21SWarner Losh 253*592ffb21SWarner Losh if ((domain != dev->pci_domain) || 254*592ffb21SWarner Losh (bus != dev->pci_bus) || 255*592ffb21SWarner Losh (slot != dev->pci_slot) || 256*592ffb21SWarner Losh (func != dev->pci_func)) { 257*592ffb21SWarner Losh ret = -EINVAL; 258*592ffb21SWarner Losh goto err; 259*592ffb21SWarner Losh } 260*592ffb21SWarner Losh return 0; 261*592ffb21SWarner Losh err: 262*592ffb21SWarner Losh return ret; 263*592ffb21SWarner Losh } 264*592ffb21SWarner Losh 265*592ffb21SWarner Losh 266*592ffb21SWarner Losh static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) 267*592ffb21SWarner Losh { 268*592ffb21SWarner Losh if ((p->busnum >> 8) != drm_get_pci_domain(dev) || 269*592ffb21SWarner Losh (p->busnum & 0xff) != dev->pci_bus || 270*592ffb21SWarner Losh p->devnum != dev->pci_slot || p->funcnum != dev->pci_func) 271*592ffb21SWarner Losh return -EINVAL; 272*592ffb21SWarner Losh 273*592ffb21SWarner Losh p->irq = dev->irq; 274*592ffb21SWarner Losh 275*592ffb21SWarner Losh DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, 276*592ffb21SWarner Losh p->irq); 277*592ffb21SWarner Losh return 0; 278*592ffb21SWarner Losh } 279*592ffb21SWarner Losh 280*592ffb21SWarner Losh int drm_pci_agp_init(struct drm_device *dev) 281*592ffb21SWarner Losh { 282*592ffb21SWarner Losh if (drm_core_has_AGP(dev)) { 283*592ffb21SWarner Losh if (drm_pci_device_is_agp(dev)) 284*592ffb21SWarner Losh dev->agp = drm_agp_init(dev); 285*592ffb21SWarner Losh if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP) 286*592ffb21SWarner Losh && (dev->agp == NULL)) { 287*592ffb21SWarner Losh DRM_ERROR("Cannot initialize the agpgart module.\n"); 288*592ffb21SWarner Losh return -EINVAL; 289*592ffb21SWarner Losh } 290*592ffb21SWarner Losh if (drm_core_has_MTRR(dev)) { 291*592ffb21SWarner Losh if (dev->agp && dev->agp->agp_info.ai_aperture_base != 0) { 292*592ffb21SWarner Losh if (drm_mtrr_add(dev->agp->agp_info.ai_aperture_base, 293*592ffb21SWarner Losh dev->agp->agp_info.ai_aperture_size, DRM_MTRR_WC) == 0) 294*592ffb21SWarner Losh dev->agp->agp_mtrr = 1; 295*592ffb21SWarner Losh else 296*592ffb21SWarner Losh dev->agp->agp_mtrr = -1; 297*592ffb21SWarner Losh } 298*592ffb21SWarner Losh } 299*592ffb21SWarner Losh } 300*592ffb21SWarner Losh return 0; 301*592ffb21SWarner Losh } 302*592ffb21SWarner Losh 303*592ffb21SWarner Losh static struct drm_bus drm_pci_bus = { 304*592ffb21SWarner Losh .bus_type = DRIVER_BUS_PCI, 305*592ffb21SWarner Losh .get_irq = drm_pci_get_irq, 306*592ffb21SWarner Losh .free_irq = drm_pci_free_irq, 307*592ffb21SWarner Losh .get_name = drm_pci_get_name, 308*592ffb21SWarner Losh .set_busid = drm_pci_set_busid, 309*592ffb21SWarner Losh .set_unique = drm_pci_set_unique, 310*592ffb21SWarner Losh .irq_by_busid = drm_pci_irq_by_busid, 311*592ffb21SWarner Losh .agp_init = drm_pci_agp_init, 312*592ffb21SWarner Losh }; 313*592ffb21SWarner Losh 314*592ffb21SWarner Losh /** 315*592ffb21SWarner Losh * Register. 316*592ffb21SWarner Losh * 317*592ffb21SWarner Losh * \param pdev - PCI device structure 318*592ffb21SWarner Losh * \param ent entry from the PCI ID table with device type flags 319*592ffb21SWarner Losh * \return zero on success or a negative number on failure. 320*592ffb21SWarner Losh * 321*592ffb21SWarner Losh * Attempt to gets inter module "drm" information. If we are first 322*592ffb21SWarner Losh * then register the character device and inter module information. 323*592ffb21SWarner Losh * Try and register, if we fail to register, backout previous work. 324*592ffb21SWarner Losh */ 325*592ffb21SWarner Losh int drm_get_pci_dev(device_t kdev, struct drm_device *dev, 326*592ffb21SWarner Losh struct drm_driver *driver) 327*592ffb21SWarner Losh { 328*592ffb21SWarner Losh int ret; 329*592ffb21SWarner Losh 330*592ffb21SWarner Losh DRM_DEBUG("\n"); 331*592ffb21SWarner Losh 332*592ffb21SWarner Losh driver->bus = &drm_pci_bus; 333*592ffb21SWarner Losh 334*592ffb21SWarner Losh dev->dev = kdev; 335*592ffb21SWarner Losh 336*592ffb21SWarner Losh dev->pci_domain = pci_get_domain(dev->dev); 337*592ffb21SWarner Losh dev->pci_bus = pci_get_bus(dev->dev); 338*592ffb21SWarner Losh dev->pci_slot = pci_get_slot(dev->dev); 339*592ffb21SWarner Losh dev->pci_func = pci_get_function(dev->dev); 340*592ffb21SWarner Losh 341*592ffb21SWarner Losh dev->pci_vendor = pci_get_vendor(dev->dev); 342*592ffb21SWarner Losh dev->pci_device = pci_get_device(dev->dev); 343*592ffb21SWarner Losh dev->pci_subvendor = pci_get_subvendor(dev->dev); 344*592ffb21SWarner Losh dev->pci_subdevice = pci_get_subdevice(dev->dev); 345*592ffb21SWarner Losh 346*592ffb21SWarner Losh sx_xlock(&drm_global_mutex); 347*592ffb21SWarner Losh 348*592ffb21SWarner Losh if ((ret = drm_fill_in_dev(dev, driver))) { 349*592ffb21SWarner Losh DRM_ERROR("Failed to fill in dev: %d\n", ret); 350*592ffb21SWarner Losh goto err_g1; 351*592ffb21SWarner Losh } 352*592ffb21SWarner Losh 353*592ffb21SWarner Losh if (drm_core_check_feature(dev, DRIVER_MODESET)) { 354*592ffb21SWarner Losh ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); 355*592ffb21SWarner Losh if (ret) 356*592ffb21SWarner Losh goto err_g2; 357*592ffb21SWarner Losh } 358*592ffb21SWarner Losh 359*592ffb21SWarner Losh if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) 360*592ffb21SWarner Losh goto err_g3; 361*592ffb21SWarner Losh 362*592ffb21SWarner Losh if (dev->driver->load) { 363*592ffb21SWarner Losh ret = dev->driver->load(dev, 364*592ffb21SWarner Losh dev->id_entry->driver_private); 365*592ffb21SWarner Losh if (ret) 366*592ffb21SWarner Losh goto err_g4; 367*592ffb21SWarner Losh } 368*592ffb21SWarner Losh 369*592ffb21SWarner Losh /* setup the grouping for the legacy output */ 370*592ffb21SWarner Losh if (drm_core_check_feature(dev, DRIVER_MODESET)) { 371*592ffb21SWarner Losh ret = drm_mode_group_init_legacy_group(dev, 372*592ffb21SWarner Losh &dev->primary->mode_group); 373*592ffb21SWarner Losh if (ret) 374*592ffb21SWarner Losh goto err_g5; 375*592ffb21SWarner Losh } 376*592ffb21SWarner Losh 377*592ffb21SWarner Losh #ifdef FREEBSD_NOTYET 378*592ffb21SWarner Losh list_add_tail(&dev->driver_item, &driver->device_list); 379*592ffb21SWarner Losh #endif /* FREEBSD_NOTYET */ 380*592ffb21SWarner Losh 381*592ffb21SWarner Losh DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", 382*592ffb21SWarner Losh driver->name, driver->major, driver->minor, driver->patchlevel, 383*592ffb21SWarner Losh driver->date, device_get_nameunit(dev->dev), dev->primary->index); 384*592ffb21SWarner Losh 385*592ffb21SWarner Losh sx_xunlock(&drm_global_mutex); 386*592ffb21SWarner Losh return 0; 387*592ffb21SWarner Losh 388*592ffb21SWarner Losh err_g5: 389*592ffb21SWarner Losh if (dev->driver->unload) 390*592ffb21SWarner Losh dev->driver->unload(dev); 391*592ffb21SWarner Losh err_g4: 392*592ffb21SWarner Losh drm_put_minor(&dev->primary); 393*592ffb21SWarner Losh err_g3: 394*592ffb21SWarner Losh if (drm_core_check_feature(dev, DRIVER_MODESET)) 395*592ffb21SWarner Losh drm_put_minor(&dev->control); 396*592ffb21SWarner Losh err_g2: 397*592ffb21SWarner Losh drm_cancel_fill_in_dev(dev); 398*592ffb21SWarner Losh err_g1: 399*592ffb21SWarner Losh sx_xunlock(&drm_global_mutex); 400*592ffb21SWarner Losh return ret; 401*592ffb21SWarner Losh } 402*592ffb21SWarner Losh EXPORT_SYMBOL(drm_get_pci_dev); 403*592ffb21SWarner Losh 404*592ffb21SWarner Losh int 405*592ffb21SWarner Losh drm_pci_enable_msi(struct drm_device *dev) 406*592ffb21SWarner Losh { 407*592ffb21SWarner Losh int msicount, ret; 408*592ffb21SWarner Losh 409*592ffb21SWarner Losh if (!drm_msi) 410*592ffb21SWarner Losh return (-ENOENT); 411*592ffb21SWarner Losh 412*592ffb21SWarner Losh msicount = pci_msi_count(dev->dev); 413*592ffb21SWarner Losh DRM_DEBUG("MSI count = %d\n", msicount); 414*592ffb21SWarner Losh if (msicount > 1) 415*592ffb21SWarner Losh msicount = 1; 416*592ffb21SWarner Losh 417*592ffb21SWarner Losh ret = pci_alloc_msi(dev->dev, &msicount); 418*592ffb21SWarner Losh if (ret == 0) { 419*592ffb21SWarner Losh DRM_INFO("MSI enabled %d message(s)\n", msicount); 420*592ffb21SWarner Losh dev->msi_enabled = 1; 421*592ffb21SWarner Losh dev->irqrid = 1; 422*592ffb21SWarner Losh } 423*592ffb21SWarner Losh 424*592ffb21SWarner Losh return (-ret); 425*592ffb21SWarner Losh } 426*592ffb21SWarner Losh 427*592ffb21SWarner Losh void 428*592ffb21SWarner Losh drm_pci_disable_msi(struct drm_device *dev) 429*592ffb21SWarner Losh { 430*592ffb21SWarner Losh 431*592ffb21SWarner Losh if (!dev->msi_enabled) 432*592ffb21SWarner Losh return; 433*592ffb21SWarner Losh 434*592ffb21SWarner Losh pci_release_msi(dev->dev); 435*592ffb21SWarner Losh dev->msi_enabled = 0; 436*592ffb21SWarner Losh dev->irqrid = 0; 437*592ffb21SWarner Losh } 438*592ffb21SWarner Losh 439*592ffb21SWarner Losh int drm_pcie_get_speed_cap_mask(struct drm_device *dev, u32 *mask) 440*592ffb21SWarner Losh { 441*592ffb21SWarner Losh device_t root; 442*592ffb21SWarner Losh int pos; 443*592ffb21SWarner Losh u32 lnkcap = 0, lnkcap2 = 0; 444*592ffb21SWarner Losh 445*592ffb21SWarner Losh *mask = 0; 446*592ffb21SWarner Losh if (!drm_pci_device_is_pcie(dev)) 447*592ffb21SWarner Losh return -EINVAL; 448*592ffb21SWarner Losh 449*592ffb21SWarner Losh root = 450*592ffb21SWarner Losh device_get_parent( /* pcib */ 451*592ffb21SWarner Losh device_get_parent( /* `-- pci */ 452*592ffb21SWarner Losh device_get_parent( /* `-- vgapci */ 453*592ffb21SWarner Losh dev->dev))); /* `-- drmn */ 454*592ffb21SWarner Losh 455*592ffb21SWarner Losh pos = 0; 456*592ffb21SWarner Losh pci_find_cap(root, PCIY_EXPRESS, &pos); 457*592ffb21SWarner Losh if (!pos) 458*592ffb21SWarner Losh return -EINVAL; 459*592ffb21SWarner Losh 460*592ffb21SWarner Losh /* we've been informed via and serverworks don't make the cut */ 461*592ffb21SWarner Losh if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA || 462*592ffb21SWarner Losh pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS) 463*592ffb21SWarner Losh return -EINVAL; 464*592ffb21SWarner Losh 465*592ffb21SWarner Losh lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4); 466*592ffb21SWarner Losh lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4); 467*592ffb21SWarner Losh 468*592ffb21SWarner Losh lnkcap &= PCIEM_LINK_CAP_MAX_SPEED; 469*592ffb21SWarner Losh lnkcap2 &= 0xfe; 470*592ffb21SWarner Losh 471*592ffb21SWarner Losh #define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */ 472*592ffb21SWarner Losh #define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */ 473*592ffb21SWarner Losh #define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */ 474*592ffb21SWarner Losh 475*592ffb21SWarner Losh if (lnkcap2) { /* PCIE GEN 3.0 */ 476*592ffb21SWarner Losh if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB) 477*592ffb21SWarner Losh *mask |= DRM_PCIE_SPEED_25; 478*592ffb21SWarner Losh if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB) 479*592ffb21SWarner Losh *mask |= DRM_PCIE_SPEED_50; 480*592ffb21SWarner Losh if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB) 481*592ffb21SWarner Losh *mask |= DRM_PCIE_SPEED_80; 482*592ffb21SWarner Losh } else { 483*592ffb21SWarner Losh if (lnkcap & 1) 484*592ffb21SWarner Losh *mask |= DRM_PCIE_SPEED_25; 485*592ffb21SWarner Losh if (lnkcap & 2) 486*592ffb21SWarner Losh *mask |= DRM_PCIE_SPEED_50; 487*592ffb21SWarner Losh } 488*592ffb21SWarner Losh 489*592ffb21SWarner Losh DRM_INFO("probing gen 2 caps for device %x:%x = %x/%x\n", pci_get_vendor(root), pci_get_device(root), lnkcap, lnkcap2); 490*592ffb21SWarner Losh return 0; 491*592ffb21SWarner Losh } 492*592ffb21SWarner Losh EXPORT_SYMBOL(drm_pcie_get_speed_cap_mask); 493