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/drm/ati_pcigart.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 /*-
    2  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
    3  * All Rights Reserved.
    4  *
    5  * Permission is hereby granted, free of charge, to any person obtaining a
    6  * copy of this software and associated documentation files (the "Software"),
    7  * to deal in the Software without restriction, including without limitation
    8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    9  * and/or sell copies of the Software, and to permit persons to whom the
   10  * Software is furnished to do so, subject to the following conditions:
   11  *
   12  * The above copyright notice and this permission notice (including the next
   13  * paragraph) shall be included in all copies or substantial portions of the
   14  * Software.
   15  *
   16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
   20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   22  * DEALINGS IN THE SOFTWARE.
   23  *
   24  * Authors:
   25  *   Gareth Hughes <gareth@valinux.com>
   26  *
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 /** @file ati_pcigart.c
   33  * Implementation of ATI's PCIGART, which provides an aperture in card virtual
   34  * address space with addresses remapped to system memory.
   35  */
   36 
   37 #include "dev/drm/drmP.h"
   38 
   39 #define ATI_PCIGART_PAGE_SIZE           4096    /* PCI GART page size */
   40 #define ATI_PCIGART_PAGE_MASK           (~(ATI_PCIGART_PAGE_SIZE-1))
   41 
   42 #define ATI_GART_NOSNOOP        0x1
   43 #define ATI_GART_WRITE          0x4
   44 #define ATI_GART_READ           0x8
   45 
   46 static void
   47 drm_ati_alloc_pcigart_table_cb(void *arg, bus_dma_segment_t *segs,
   48                                int nsegs, int error)
   49 {
   50         struct drm_dma_handle *dmah = arg;
   51 
   52         if (error != 0)
   53                 return;
   54 
   55         KASSERT(nsegs == 1,
   56             ("drm_ati_alloc_pcigart_table_cb: bad dma segment count"));
   57 
   58         dmah->busaddr = segs[0].ds_addr;
   59 }
   60 
   61 static int
   62 drm_ati_alloc_pcigart_table(struct drm_device *dev,
   63                             struct drm_ati_pcigart_info *gart_info)
   64 {
   65         struct drm_dma_handle *dmah;
   66         int flags, ret;
   67 
   68         dmah = malloc(sizeof(struct drm_dma_handle), DRM_MEM_DMA,
   69             M_ZERO | M_NOWAIT);
   70         if (dmah == NULL)
   71                 return ENOMEM;
   72 
   73         DRM_UNLOCK();
   74         ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */
   75             gart_info->table_mask, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */
   76             NULL, NULL, /* filtfunc, filtfuncargs */
   77             gart_info->table_size, 1, /* maxsize, nsegs */
   78             gart_info->table_size, /* maxsegsize */
   79             0, NULL, NULL, /* flags, lockfunc, lockfuncargs */
   80             &dmah->tag);
   81         if (ret != 0) {
   82                 free(dmah, DRM_MEM_DMA);
   83                 return ENOMEM;
   84         }
   85 
   86         flags = BUS_DMA_WAITOK | BUS_DMA_ZERO;
   87         if (gart_info->gart_reg_if == DRM_ATI_GART_IGP)
   88             flags |= BUS_DMA_NOCACHE;
   89         
   90         ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, flags, &dmah->map);
   91         if (ret != 0) {
   92                 bus_dma_tag_destroy(dmah->tag);
   93                 free(dmah, DRM_MEM_DMA);
   94                 return ENOMEM;
   95         }
   96         DRM_LOCK();
   97 
   98         ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr,
   99             gart_info->table_size, drm_ati_alloc_pcigart_table_cb, dmah,
  100             BUS_DMA_NOWAIT);
  101         if (ret != 0) {
  102                 bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
  103                 bus_dma_tag_destroy(dmah->tag);
  104                 free(dmah, DRM_MEM_DMA);
  105                 return ENOMEM;
  106         }
  107 
  108         gart_info->dmah = dmah;
  109 
  110         return 0;
  111 }
  112 
  113 static void
  114 drm_ati_free_pcigart_table(struct drm_device *dev,
  115                            struct drm_ati_pcigart_info *gart_info)
  116 {
  117         struct drm_dma_handle *dmah = gart_info->dmah;
  118 
  119         bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map);
  120         bus_dma_tag_destroy(dmah->tag);
  121         free(dmah, DRM_MEM_DMA);
  122         gart_info->dmah = NULL;
  123 }
  124 
  125 int
  126 drm_ati_pcigart_cleanup(struct drm_device *dev,
  127                         struct drm_ati_pcigart_info *gart_info)
  128 {
  129         /* we need to support large memory configurations */
  130         if (dev->sg == NULL) {
  131                 DRM_ERROR("no scatter/gather memory!\n");
  132                 return 0;
  133         }
  134 
  135         if (gart_info->bus_addr) {
  136                 if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
  137                         gart_info->bus_addr = 0;
  138                         if (gart_info->dmah)
  139                                 drm_ati_free_pcigart_table(dev, gart_info);
  140                 }
  141         }
  142 
  143         return 1;
  144 }
  145 
  146 int
  147 drm_ati_pcigart_init(struct drm_device *dev,
  148                      struct drm_ati_pcigart_info *gart_info)
  149 {
  150         void *address = NULL;
  151         unsigned long pages;
  152         u32 *pci_gart, page_base;
  153         dma_addr_t bus_address = 0;
  154         dma_addr_t entry_addr;
  155         int i, j, ret = 0;
  156         int max_pages;
  157 
  158         /* we need to support large memory configurations */
  159         if (dev->sg == NULL) {
  160                 DRM_ERROR("no scatter/gather memory!\n");
  161                 goto done;
  162         }
  163 
  164         if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
  165                 DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
  166 
  167                 ret = drm_ati_alloc_pcigart_table(dev, gart_info);
  168                 if (ret) {
  169                         DRM_ERROR("cannot allocate PCI GART page!\n");
  170                         goto done;
  171                 }
  172 
  173                 address = (void *)gart_info->dmah->vaddr;
  174                 bus_address = gart_info->dmah->busaddr;
  175         } else {
  176                 address = gart_info->addr;
  177                 bus_address = gart_info->bus_addr;
  178                 DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n",
  179                           (unsigned int)bus_address, (unsigned long)address);
  180         }
  181 
  182         pci_gart = (u32 *) address;
  183 
  184         max_pages = (gart_info->table_size / sizeof(u32));
  185         pages = (dev->sg->pages <= max_pages)
  186             ? dev->sg->pages : max_pages;
  187 
  188         memset(pci_gart, 0, max_pages * sizeof(u32));
  189 
  190         KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small"));
  191 
  192         for (i = 0; i < pages; i++) {
  193                 entry_addr = dev->sg->busaddr[i];
  194                 for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
  195                         page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK;
  196                         switch(gart_info->gart_reg_if) {
  197                         case DRM_ATI_GART_IGP:
  198                                 page_base |=
  199                                     (upper_32_bits(entry_addr) & 0xff) << 4;
  200                                 page_base |= ATI_GART_READ | ATI_GART_WRITE;
  201                                 page_base |= ATI_GART_NOSNOOP;
  202                                 break;
  203                         case DRM_ATI_GART_PCIE:
  204                                 page_base >>= 8;
  205                                 page_base |=
  206                                     (upper_32_bits(entry_addr) & 0xff) << 24;
  207                                 page_base |= ATI_GART_READ | ATI_GART_WRITE;
  208                                 page_base |= ATI_GART_NOSNOOP;
  209                                 break;
  210                         default:
  211                         case DRM_ATI_GART_PCI:
  212                                 break;
  213                         }
  214                         *pci_gart = cpu_to_le32(page_base);
  215                         pci_gart++;
  216                         entry_addr += ATI_PCIGART_PAGE_SIZE;
  217                 }
  218         }
  219 
  220         ret = 1;
  221 
  222     done:
  223         gart_info->addr = address;
  224         gart_info->bus_addr = bus_address;
  225         return ret;
  226 }

Cache object: f74e5911ceed2c961f084d02a46f8b39


[ 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.