The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/drm_pci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0f984583fe603919f4d16d70817f0bb0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.