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/pci/agp.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 /*      $NetBSD: agp.c,v 1.32 2004/02/13 11:36:22 wiz Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2000 Doug Rabson
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  *      $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $
   29  */
   30 
   31 /*
   32  * Copyright (c) 2001 Wasabi Systems, Inc.
   33  * All rights reserved.
   34  *
   35  * Written by Frank van der Linden for Wasabi Systems, Inc.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice, this list of conditions and the following disclaimer.
   42  * 2. Redistributions in binary form must reproduce the above copyright
   43  *    notice, this list of conditions and the following disclaimer in the
   44  *    documentation and/or other materials provided with the distribution.
   45  * 3. All advertising materials mentioning features or use of this software
   46  *    must display the following acknowledgement:
   47  *      This product includes software developed for the NetBSD Project by
   48  *      Wasabi Systems, Inc.
   49  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   50  *    or promote products derived from this software without specific prior
   51  *    written permission.
   52  *
   53  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   55  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   56  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   57  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   58  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   59  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   60  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   61  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   62  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   63  * POSSIBILITY OF SUCH DAMAGE.
   64  */
   65 
   66 
   67 #include <sys/cdefs.h>
   68 __KERNEL_RCSID(0, "$NetBSD: agp.c,v 1.32 2004/02/13 11:36:22 wiz Exp $");
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/malloc.h>
   73 #include <sys/kernel.h>
   74 #include <sys/device.h>
   75 #include <sys/conf.h>
   76 #include <sys/ioctl.h>
   77 #include <sys/fcntl.h>
   78 #include <sys/agpio.h>
   79 #include <sys/proc.h>
   80 
   81 #include <uvm/uvm_extern.h>
   82 
   83 #include <dev/pci/pcireg.h>
   84 #include <dev/pci/pcivar.h>
   85 #include <dev/pci/agpvar.h>
   86 #include <dev/pci/agpreg.h>
   87 #include <dev/pci/pcidevs.h>
   88 
   89 #include <machine/bus.h>
   90 
   91 MALLOC_DEFINE(M_AGP, "AGP", "AGP memory");
   92 
   93 /* Helper functions for implementing chipset mini drivers. */
   94 /* XXXfvdl get rid of this one. */
   95 
   96 extern struct cfdriver agp_cd;
   97 
   98 dev_type_open(agpopen);
   99 dev_type_close(agpclose);
  100 dev_type_ioctl(agpioctl);
  101 dev_type_mmap(agpmmap);
  102 
  103 const struct cdevsw agp_cdevsw = {
  104         agpopen, agpclose, noread, nowrite, agpioctl,
  105         nostop, notty, nopoll, agpmmap, nokqfilter,
  106 };
  107 
  108 int agpmatch(struct device *, struct cfdata *, void *);
  109 void agpattach(struct device *, struct device *, void *);
  110 
  111 CFATTACH_DECL(agp, sizeof(struct agp_softc),
  112     agpmatch, agpattach, NULL, NULL);
  113 
  114 static int agp_info_user(struct agp_softc *, agp_info *);
  115 static int agp_setup_user(struct agp_softc *, agp_setup *);
  116 static int agp_allocate_user(struct agp_softc *, agp_allocate *);
  117 static int agp_deallocate_user(struct agp_softc *, int);
  118 static int agp_bind_user(struct agp_softc *, agp_bind *);
  119 static int agp_unbind_user(struct agp_softc *, agp_unbind *);
  120 static int agpdev_match(struct pci_attach_args *);
  121 
  122 #include "agp_ali.h"
  123 #include "agp_amd.h"
  124 #include "agp_i810.h"
  125 #include "agp_intel.h"
  126 #include "agp_sis.h"
  127 #include "agp_via.h"
  128 
  129 const struct agp_product {
  130         uint32_t        ap_vendor;
  131         uint32_t        ap_product;
  132         int             (*ap_match)(const struct pci_attach_args *);
  133         int             (*ap_attach)(struct device *, struct device *, void *);
  134 } agp_products[] = {
  135 #if NAGP_ALI > 0
  136         { PCI_VENDOR_ALI,       -1,
  137           NULL,                 agp_ali_attach },
  138 #endif
  139 
  140 #if NAGP_AMD > 0
  141         { PCI_VENDOR_AMD,       -1,
  142           agp_amd_match,        agp_amd_attach },
  143 #endif
  144 
  145 #if NAGP_I810 > 0
  146         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82810_MCH,
  147           NULL,                 agp_i810_attach },
  148         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82810_DC100_MCH,
  149           NULL,                 agp_i810_attach },
  150         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82810E_MCH,
  151           NULL,                 agp_i810_attach },
  152         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82815_FULL_HUB,
  153           NULL,                 agp_i810_attach },
  154         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82840_HB,
  155           NULL,                 agp_i810_attach },
  156         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82830MP_IO_1,
  157           NULL,                 agp_i810_attach },
  158         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82845G_DRAM,
  159           NULL,                 agp_i810_attach },
  160         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82855GM_MCH,
  161           NULL,                 agp_i810_attach },
  162         { PCI_VENDOR_INTEL,     PCI_PRODUCT_INTEL_82865_HB,
  163           NULL,                 agp_i810_attach },
  164 #endif
  165 
  166 #if NAGP_INTEL > 0
  167         { PCI_VENDOR_INTEL,     -1,
  168           NULL,                 agp_intel_attach },
  169 #endif
  170 
  171 #if NAGP_SIS > 0
  172         { PCI_VENDOR_SIS,       -1,
  173           NULL,                 agp_sis_attach },
  174 #endif
  175 
  176 #if NAGP_VIA > 0
  177         { PCI_VENDOR_VIATECH,   -1,
  178           NULL,                 agp_via_attach },
  179 #endif
  180 
  181         { 0,                    0,
  182           NULL,                 NULL },
  183 };
  184 
  185 static const struct agp_product *
  186 agp_lookup(const struct pci_attach_args *pa)
  187 {
  188         const struct agp_product *ap;
  189 
  190         /* First find the vendor. */
  191         for (ap = agp_products; ap->ap_attach != NULL; ap++) {
  192                 if (PCI_VENDOR(pa->pa_id) == ap->ap_vendor)
  193                         break;
  194         }
  195 
  196         if (ap->ap_attach == NULL)
  197                 return (NULL);
  198 
  199         /* Now find the product within the vendor's domain. */
  200         for (; ap->ap_attach != NULL; ap++) {
  201                 if (PCI_VENDOR(pa->pa_id) != ap->ap_vendor) {
  202                         /* Ran out of this vendor's section of the table. */
  203                         return (NULL);
  204                 }
  205                 if (ap->ap_product == PCI_PRODUCT(pa->pa_id)) {
  206                         /* Exact match. */
  207                         break;
  208                 }
  209                 if (ap->ap_product == (uint32_t) -1) {
  210                         /* Wildcard match. */
  211                         break;
  212                 }
  213         }
  214 
  215         if (ap->ap_attach == NULL)
  216                 return (NULL);
  217 
  218         /* Now let the product-specific driver filter the match. */
  219         if (ap->ap_match != NULL && (*ap->ap_match)(pa) == 0)
  220                 return (NULL);
  221 
  222         return (ap);
  223 }
  224 
  225 int
  226 agpmatch(struct device *parent, struct cfdata *match, void *aux)
  227 {
  228         struct agpbus_attach_args *apa = aux;
  229         struct pci_attach_args *pa = &apa->apa_pci_args;
  230 
  231         if (strcmp(apa->apa_busname, "agp") != 0)
  232                 return (0);
  233 
  234         if (agp_lookup(pa) == NULL)
  235                 return (0);
  236 
  237         return (1);
  238 }
  239 
  240 static int agp_max[][2] = {
  241         {0,     0},
  242         {32,    4},
  243         {64,    28},
  244         {128,   96},
  245         {256,   204},
  246         {512,   440},
  247         {1024,  942},
  248         {2048,  1920},
  249         {4096,  3932}
  250 };
  251 #define agp_max_size    (sizeof(agp_max) / sizeof(agp_max[0]))
  252 
  253 void
  254 agpattach(struct device *parent, struct device *self, void *aux)
  255 {
  256         struct agpbus_attach_args *apa = aux;
  257         struct pci_attach_args *pa = &apa->apa_pci_args;
  258         struct agp_softc *sc = (void *)self;
  259         const struct agp_product *ap;
  260         int memsize, i, ret;
  261 
  262         ap = agp_lookup(pa);
  263         if (ap == NULL) {
  264                 printf("\n");
  265                 panic("agpattach: impossible");
  266         }
  267 
  268         aprint_naive(": AGP controller\n");
  269 
  270         sc->as_dmat = pa->pa_dmat;
  271         sc->as_pc = pa->pa_pc;
  272         sc->as_tag = pa->pa_tag;
  273         sc->as_id = pa->pa_id;
  274 
  275         /*
  276          * Work out an upper bound for agp memory allocation. This
  277          * uses a heurisitc table from the Linux driver.
  278          */
  279         memsize = ptoa(physmem) >> 20;
  280         for (i = 0; i < agp_max_size; i++) {
  281                 if (memsize <= agp_max[i][0])
  282                         break;
  283         }
  284         if (i == agp_max_size)
  285                 i = agp_max_size - 1;
  286         sc->as_maxmem = agp_max[i][1] << 20U;
  287 
  288         /*
  289          * The lock is used to prevent re-entry to
  290          * agp_generic_bind_memory() since that function can sleep.
  291          */
  292         lockinit(&sc->as_lock, PZERO|PCATCH, "agplk", 0, 0);
  293 
  294         TAILQ_INIT(&sc->as_memory);
  295 
  296         ret = (*ap->ap_attach)(parent, self, pa);
  297         if (ret == 0)
  298                 aprint_normal(": aperture at 0x%lx, size 0x%lx\n",
  299                     (unsigned long)sc->as_apaddr,
  300                     (unsigned long)AGP_GET_APERTURE(sc));
  301         else
  302                 sc->as_chipc = NULL;
  303 }
  304 
  305 int
  306 agp_map_aperture(struct pci_attach_args *pa, struct agp_softc *sc)
  307 {
  308         /*
  309          * Find the aperture. Don't map it (yet), this would
  310          * eat KVA.
  311          */
  312         if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
  313             PCI_MAPREG_TYPE_MEM, &sc->as_apaddr, &sc->as_apsize,
  314             &sc->as_apflags) != 0)
  315                 return ENXIO;
  316 
  317         sc->as_apt = pa->pa_memt;
  318 
  319         return 0;
  320 }
  321 
  322 struct agp_gatt *
  323 agp_alloc_gatt(struct agp_softc *sc)
  324 {
  325         u_int32_t apsize = AGP_GET_APERTURE(sc);
  326         u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
  327         struct agp_gatt *gatt;
  328         int dummyseg;
  329 
  330         gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
  331         if (!gatt)
  332                 return NULL;
  333         gatt->ag_entries = entries;
  334 
  335         if (agp_alloc_dmamem(sc->as_dmat, entries * sizeof(u_int32_t),
  336             0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual,
  337             &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0)
  338                 return NULL;
  339 
  340         gatt->ag_size = entries * sizeof(u_int32_t);
  341         memset(gatt->ag_virtual, 0, gatt->ag_size);
  342         agp_flush_cache();
  343 
  344         return gatt;
  345 }
  346 
  347 void
  348 agp_free_gatt(struct agp_softc *sc, struct agp_gatt *gatt)
  349 {
  350         agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap,
  351             (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1);
  352         free(gatt, M_AGP);
  353 }
  354 
  355 
  356 int
  357 agp_generic_detach(struct agp_softc *sc)
  358 {
  359         lockmgr(&sc->as_lock, LK_DRAIN, 0);
  360         agp_flush_cache();
  361         return 0;
  362 }
  363 
  364 static int
  365 agpdev_match(struct pci_attach_args *pa)
  366 {
  367         if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
  368             PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA)
  369                 if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
  370                     NULL, NULL))
  371                 return 1;
  372 
  373         return 0;
  374 }
  375 
  376 int
  377 agp_generic_enable(struct agp_softc *sc, u_int32_t mode)
  378 {
  379         struct pci_attach_args pa;
  380         pcireg_t tstatus, mstatus;
  381         pcireg_t command;
  382         int rq, sba, fw, rate, capoff;
  383 
  384         if (pci_find_device(&pa, agpdev_match) == 0 ||
  385             pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP,
  386              &capoff, NULL) == 0) {
  387                 printf("%s: can't find display\n", sc->as_dev.dv_xname);
  388                 return ENXIO;
  389         }
  390 
  391         tstatus = pci_conf_read(sc->as_pc, sc->as_tag,
  392             sc->as_capoff + AGP_STATUS);
  393         mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag,
  394             capoff + AGP_STATUS);
  395 
  396         /* Set RQ to the min of mode, tstatus and mstatus */
  397         rq = AGP_MODE_GET_RQ(mode);
  398         if (AGP_MODE_GET_RQ(tstatus) < rq)
  399                 rq = AGP_MODE_GET_RQ(tstatus);
  400         if (AGP_MODE_GET_RQ(mstatus) < rq)
  401                 rq = AGP_MODE_GET_RQ(mstatus);
  402 
  403         /* Set SBA if all three can deal with SBA */
  404         sba = (AGP_MODE_GET_SBA(tstatus)
  405                & AGP_MODE_GET_SBA(mstatus)
  406                & AGP_MODE_GET_SBA(mode));
  407 
  408         /* Similar for FW */
  409         fw = (AGP_MODE_GET_FW(tstatus)
  410                & AGP_MODE_GET_FW(mstatus)
  411                & AGP_MODE_GET_FW(mode));
  412 
  413         /* Figure out the max rate */
  414         rate = (AGP_MODE_GET_RATE(tstatus)
  415                 & AGP_MODE_GET_RATE(mstatus)
  416                 & AGP_MODE_GET_RATE(mode));
  417         if (rate & AGP_MODE_RATE_4x)
  418                 rate = AGP_MODE_RATE_4x;
  419         else if (rate & AGP_MODE_RATE_2x)
  420                 rate = AGP_MODE_RATE_2x;
  421         else
  422                 rate = AGP_MODE_RATE_1x;
  423 
  424         /* Construct the new mode word and tell the hardware */
  425         command = AGP_MODE_SET_RQ(0, rq);
  426         command = AGP_MODE_SET_SBA(command, sba);
  427         command = AGP_MODE_SET_FW(command, fw);
  428         command = AGP_MODE_SET_RATE(command, rate);
  429         command = AGP_MODE_SET_AGP(command, 1);
  430         pci_conf_write(sc->as_pc, sc->as_tag,
  431             sc->as_capoff + AGP_COMMAND, command);
  432         pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command);
  433 
  434         return 0;
  435 }
  436 
  437 struct agp_memory *
  438 agp_generic_alloc_memory(struct agp_softc *sc, int type, vsize_t size)
  439 {
  440         struct agp_memory *mem;
  441 
  442         if ((size & (AGP_PAGE_SIZE - 1)) != 0)
  443                 return 0;
  444 
  445         if (sc->as_allocated + size > sc->as_maxmem)
  446                 return 0;
  447 
  448         if (type != 0) {
  449                 printf("agp_generic_alloc_memory: unsupported type %d\n",
  450                        type);
  451                 return 0;
  452         }
  453 
  454         mem = malloc(sizeof *mem, M_AGP, M_WAITOK);
  455         if (mem == NULL)
  456                 return NULL;
  457 
  458         if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1,
  459                               size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) {
  460                 free(mem, M_AGP);
  461                 return NULL;
  462         }
  463 
  464         mem->am_id = sc->as_nextid++;
  465         mem->am_size = size;
  466         mem->am_type = 0;
  467         mem->am_physical = 0;
  468         mem->am_offset = 0;
  469         mem->am_is_bound = 0;
  470         TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
  471         sc->as_allocated += size;
  472 
  473         return mem;
  474 }
  475 
  476 int
  477 agp_generic_free_memory(struct agp_softc *sc, struct agp_memory *mem)
  478 {
  479         if (mem->am_is_bound)
  480                 return EBUSY;
  481 
  482         sc->as_allocated -= mem->am_size;
  483         TAILQ_REMOVE(&sc->as_memory, mem, am_link);
  484         bus_dmamap_destroy(sc->as_dmat, mem->am_dmamap);
  485         free(mem, M_AGP);
  486         return 0;
  487 }
  488 
  489 int
  490 agp_generic_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
  491                         off_t offset)
  492 {
  493         off_t i, k;
  494         bus_size_t done, j;
  495         int error;
  496         bus_dma_segment_t *segs, *seg;
  497         bus_addr_t pa;
  498         int contigpages, nseg;
  499 
  500         lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0);
  501 
  502         if (mem->am_is_bound) {
  503                 printf("%s: memory already bound\n", sc->as_dev.dv_xname);
  504                 lockmgr(&sc->as_lock, LK_RELEASE, 0);
  505                 return EINVAL;
  506         }
  507         
  508         if (offset < 0
  509             || (offset & (AGP_PAGE_SIZE - 1)) != 0
  510             || offset + mem->am_size > AGP_GET_APERTURE(sc)) {
  511                 printf("%s: binding memory at bad offset %#lx\n",
  512                               sc->as_dev.dv_xname, (unsigned long) offset);
  513                 lockmgr(&sc->as_lock, LK_RELEASE, 0);
  514                 return EINVAL;
  515         }
  516 
  517         /*
  518          * XXXfvdl
  519          * The memory here needs to be directly accessable from the
  520          * AGP video card, so it should be allocated using bus_dma.
  521          * However, it need not be contiguous, since individual pages
  522          * are translated using the GATT.
  523          *
  524          * Using a large chunk of contiguous memory may get in the way
  525          * of other subsystems that may need one, so we try to be friendly
  526          * and ask for allocation in chunks of a minimum of 8 pages
  527          * of contiguous memory on average, falling back to 4, 2 and 1
  528          * if really needed. Larger chunks are preferred, since allocating
  529          * a bus_dma_segment per page would be overkill.
  530          */
  531 
  532         for (contigpages = 8; contigpages > 0; contigpages >>= 1) {
  533                 nseg = (mem->am_size / (contigpages * PAGE_SIZE)) + 1;
  534                 segs = malloc(nseg * sizeof *segs, M_AGP, M_WAITOK);
  535                 if (segs == NULL) {
  536                         lockmgr(&sc->as_lock, LK_RELEASE, 0);
  537                         return ENOMEM;
  538                 }
  539                 if (bus_dmamem_alloc(sc->as_dmat, mem->am_size, PAGE_SIZE, 0,
  540                                      segs, nseg, &mem->am_nseg,
  541                                      contigpages > 1 ?
  542                                      BUS_DMA_NOWAIT : BUS_DMA_WAITOK) != 0) {
  543                         free(segs, M_AGP);
  544                         continue;
  545                 }
  546                 if (bus_dmamem_map(sc->as_dmat, segs, mem->am_nseg,
  547                     mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK) != 0) {
  548                         bus_dmamem_free(sc->as_dmat, segs, mem->am_nseg);
  549                         free(segs, M_AGP);
  550                         continue;
  551                 }
  552                 if (bus_dmamap_load(sc->as_dmat, mem->am_dmamap,
  553                     mem->am_virtual, mem->am_size, NULL, BUS_DMA_WAITOK) != 0) {
  554                         bus_dmamem_unmap(sc->as_dmat, mem->am_virtual,  
  555                             mem->am_size);
  556                         bus_dmamem_free(sc->as_dmat, segs, mem->am_nseg);
  557                         free(segs, M_AGP);
  558                         continue;
  559                 }
  560                 mem->am_dmaseg = segs;
  561                 break;
  562         }
  563 
  564         if (contigpages == 0) {
  565                 lockmgr(&sc->as_lock, LK_RELEASE, 0);
  566                 return ENOMEM;
  567         }
  568 
  569 
  570         /*
  571          * Bind the individual pages and flush the chipset's
  572          * TLB.
  573          */
  574         done = 0;
  575         for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) {
  576                 seg = &mem->am_dmamap->dm_segs[i];
  577                 /*
  578                  * Install entries in the GATT, making sure that if
  579                  * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not
  580                  * aligned to PAGE_SIZE, we don't modify too many GATT 
  581                  * entries.
  582                  */
  583                 for (j = 0; j < seg->ds_len && (done + j) < mem->am_size;
  584                      j += AGP_PAGE_SIZE) {
  585                         pa = seg->ds_addr + j;
  586                         AGP_DPF("binding offset %#lx to pa %#lx\n",
  587                                 (unsigned long)(offset + done + j),
  588                                 (unsigned long)pa);
  589                         error = AGP_BIND_PAGE(sc, offset + done + j, pa);
  590                         if (error) {
  591                                 /*
  592                                  * Bail out. Reverse all the mappings
  593                                  * and unwire the pages.
  594                                  */
  595                                 for (k = 0; k < done + j; k += AGP_PAGE_SIZE)
  596                                         AGP_UNBIND_PAGE(sc, offset + k);
  597 
  598                                 bus_dmamap_unload(sc->as_dmat, mem->am_dmamap);
  599                                 bus_dmamem_unmap(sc->as_dmat, mem->am_virtual,
  600                                                  mem->am_size);
  601                                 bus_dmamem_free(sc->as_dmat, mem->am_dmaseg,
  602                                                 mem->am_nseg);
  603                                 free(mem->am_dmaseg, M_AGP);
  604                                 lockmgr(&sc->as_lock, LK_RELEASE, 0);
  605                                 return error;
  606                         }
  607                 }
  608                 done += seg->ds_len;
  609         }
  610 
  611         /*
  612          * Flush the CPU cache since we are providing a new mapping
  613          * for these pages.
  614          */
  615         agp_flush_cache();
  616 
  617         /*
  618          * Make sure the chipset gets the new mappings.
  619          */
  620         AGP_FLUSH_TLB(sc);
  621 
  622         mem->am_offset = offset;
  623         mem->am_is_bound = 1;
  624 
  625         lockmgr(&sc->as_lock, LK_RELEASE, 0);
  626 
  627         return 0;
  628 }
  629 
  630 int
  631 agp_generic_unbind_memory(struct agp_softc *sc, struct agp_memory *mem)
  632 {
  633         int i;
  634 
  635         lockmgr(&sc->as_lock, LK_EXCLUSIVE, 0);
  636 
  637         if (!mem->am_is_bound) {
  638                 printf("%s: memory is not bound\n", sc->as_dev.dv_xname);
  639                 lockmgr(&sc->as_lock, LK_RELEASE, 0);
  640                 return EINVAL;
  641         }
  642 
  643 
  644         /*
  645          * Unbind the individual pages and flush the chipset's
  646          * TLB. Unwire the pages so they can be swapped.
  647          */
  648         for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
  649                 AGP_UNBIND_PAGE(sc, mem->am_offset + i);
  650                 
  651         agp_flush_cache();
  652         AGP_FLUSH_TLB(sc);
  653 
  654         bus_dmamap_unload(sc->as_dmat, mem->am_dmamap);
  655         bus_dmamem_unmap(sc->as_dmat, mem->am_virtual, mem->am_size);
  656         bus_dmamem_free(sc->as_dmat, mem->am_dmaseg, mem->am_nseg);
  657 
  658         free(mem->am_dmaseg, M_AGP);
  659 
  660         mem->am_offset = 0;
  661         mem->am_is_bound = 0;
  662 
  663         lockmgr(&sc->as_lock, LK_RELEASE, 0);
  664 
  665         return 0;
  666 }
  667 
  668 /* Helper functions for implementing user/kernel api */
  669 
  670 static int
  671 agp_acquire_helper(struct agp_softc *sc, enum agp_acquire_state state)
  672 {
  673         if (sc->as_state != AGP_ACQUIRE_FREE)
  674                 return EBUSY;
  675         sc->as_state = state;
  676 
  677         return 0;
  678 }
  679 
  680 static int
  681 agp_release_helper(struct agp_softc *sc, enum agp_acquire_state state)
  682 {
  683         struct agp_memory *mem;
  684 
  685         if (sc->as_state == AGP_ACQUIRE_FREE)
  686                 return 0;
  687 
  688         if (sc->as_state != state)
  689                 return EBUSY;
  690 
  691         /*
  692          * Clear out outstanding aperture mappings.
  693          * (should not be necessary, done by caller)
  694          */
  695         TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
  696                 if (mem->am_is_bound) {
  697                         printf("agp_release_helper: mem %d is bound\n",
  698                                mem->am_id);
  699                         AGP_UNBIND_MEMORY(sc, mem);
  700                 }
  701         }
  702 
  703         sc->as_state = AGP_ACQUIRE_FREE;
  704         return 0;
  705 }
  706 
  707 static struct agp_memory *
  708 agp_find_memory(struct agp_softc *sc, int id)
  709 {
  710         struct agp_memory *mem;
  711 
  712         AGP_DPF("searching for memory block %d\n", id);
  713         TAILQ_FOREACH(mem, &sc->as_memory, am_link) {
  714                 AGP_DPF("considering memory block %d\n", mem->am_id);
  715                 if (mem->am_id == id)
  716                         return mem;
  717         }
  718         return 0;
  719 }
  720 
  721 /* Implementation of the userland ioctl api */
  722 
  723 static int
  724 agp_info_user(struct agp_softc *sc, agp_info *info)
  725 {
  726         memset(info, 0, sizeof *info);
  727         info->bridge_id = sc->as_id;
  728         if (sc->as_capoff != 0)
  729                 info->agp_mode = pci_conf_read(sc->as_pc, sc->as_tag,
  730                                                sc->as_capoff + AGP_STATUS);
  731         else
  732                 info->agp_mode = 0; /* i810 doesn't have real AGP */
  733         info->aper_base = sc->as_apaddr;
  734         info->aper_size = AGP_GET_APERTURE(sc) >> 20;
  735         info->pg_total = info->pg_system = sc->as_maxmem >> AGP_PAGE_SHIFT;
  736         info->pg_used = sc->as_allocated >> AGP_PAGE_SHIFT;
  737 
  738         return 0;
  739 }
  740 
  741 static int
  742 agp_setup_user(struct agp_softc *sc, agp_setup *setup)
  743 {
  744         return AGP_ENABLE(sc, setup->agp_mode);
  745 }
  746 
  747 static int
  748 agp_allocate_user(struct agp_softc *sc, agp_allocate *alloc)
  749 {
  750         struct agp_memory *mem;
  751 
  752         mem = AGP_ALLOC_MEMORY(sc,
  753                                alloc->type,
  754                                alloc->pg_count << AGP_PAGE_SHIFT);
  755         if (mem) {
  756                 alloc->key = mem->am_id;
  757                 alloc->physical = mem->am_physical;
  758                 return 0;
  759         } else {
  760                 return ENOMEM;
  761         }
  762 }
  763 
  764 static int
  765 agp_deallocate_user(struct agp_softc *sc, int id)
  766 {
  767         struct agp_memory *mem = agp_find_memory(sc, id);
  768 
  769         if (mem) {
  770                 AGP_FREE_MEMORY(sc, mem);
  771                 return 0;
  772         } else {
  773                 return ENOENT;
  774         }
  775 }
  776 
  777 static int
  778 agp_bind_user(struct agp_softc *sc, agp_bind *bind)
  779 {
  780         struct agp_memory *mem = agp_find_memory(sc, bind->key);
  781 
  782         if (!mem)
  783                 return ENOENT;
  784 
  785         return AGP_BIND_MEMORY(sc, mem, bind->pg_start << AGP_PAGE_SHIFT);
  786 }
  787 
  788 static int
  789 agp_unbind_user(struct agp_softc *sc, agp_unbind *unbind)
  790 {
  791         struct agp_memory *mem = agp_find_memory(sc, unbind->key);
  792 
  793         if (!mem)
  794                 return ENOENT;
  795 
  796         return AGP_UNBIND_MEMORY(sc, mem);
  797 }
  798 
  799 int
  800 agpopen(dev_t dev, int oflags, int devtype, struct proc *p)
  801 {
  802         struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev));
  803 
  804         if (sc == NULL)
  805                 return ENXIO;
  806 
  807         if (sc->as_chipc == NULL)
  808                 return ENXIO;
  809 
  810         if (!sc->as_isopen)
  811                 sc->as_isopen = 1;
  812         else
  813                 return EBUSY;
  814 
  815         return 0;
  816 }
  817 
  818 int
  819 agpclose(dev_t dev, int fflag, int devtype, struct proc *p)
  820 {
  821         struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev));
  822         struct agp_memory *mem;
  823 
  824         /*
  825          * Clear the GATT and force release on last close
  826          */
  827         if (sc->as_state == AGP_ACQUIRE_USER) {
  828                 while ((mem = TAILQ_FIRST(&sc->as_memory))) {
  829                         if (mem->am_is_bound) {
  830                                 printf("agpclose: mem %d is bound\n",
  831                                        mem->am_id);
  832                                 AGP_UNBIND_MEMORY(sc, mem);
  833                         }
  834                         /*
  835                          * XXX it is not documented, but if the protocol allows
  836                          * allocate->acquire->bind, it would be possible that
  837                          * memory ranges are allocated by the kernel here,
  838                          * which we shouldn't free. We'd have to keep track of
  839                          * the memory range's owner.
  840                          * The kernel API is unsed yet, so we get away with
  841                          * freeing all.
  842                          */
  843                         AGP_FREE_MEMORY(sc, mem);
  844                 }
  845                 agp_release_helper(sc, AGP_ACQUIRE_USER);
  846         }
  847         sc->as_isopen = 0;
  848 
  849         return 0;
  850 }
  851 
  852 int
  853 agpioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
  854 {
  855         struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev));
  856 
  857         if (sc == NULL)
  858                 return ENODEV;
  859 
  860         if ((fflag & FWRITE) == 0 && cmd != AGPIOC_INFO)
  861                 return EPERM;
  862 
  863         switch (cmd) {
  864         case AGPIOC_INFO:
  865                 return agp_info_user(sc, (agp_info *) data);
  866 
  867         case AGPIOC_ACQUIRE:
  868                 return agp_acquire_helper(sc, AGP_ACQUIRE_USER);
  869 
  870         case AGPIOC_RELEASE:
  871                 return agp_release_helper(sc, AGP_ACQUIRE_USER);
  872 
  873         case AGPIOC_SETUP:
  874                 return agp_setup_user(sc, (agp_setup *)data);
  875 
  876         case AGPIOC_ALLOCATE:
  877                 return agp_allocate_user(sc, (agp_allocate *)data);
  878 
  879         case AGPIOC_DEALLOCATE:
  880                 return agp_deallocate_user(sc, *(int *) data);
  881 
  882         case AGPIOC_BIND:
  883                 return agp_bind_user(sc, (agp_bind *)data);
  884 
  885         case AGPIOC_UNBIND:
  886                 return agp_unbind_user(sc, (agp_unbind *)data);
  887 
  888         }
  889 
  890         return EINVAL;
  891 }
  892 
  893 paddr_t
  894 agpmmap(dev_t dev, off_t offset, int prot)
  895 {
  896         struct agp_softc *sc = device_lookup(&agp_cd, AGPUNIT(dev));
  897 
  898         if (offset > AGP_GET_APERTURE(sc))
  899                 return -1;
  900 
  901         return (bus_space_mmap(sc->as_apt, sc->as_apaddr, offset, prot,
  902             BUS_SPACE_MAP_LINEAR));
  903 }
  904 
  905 /* Implementation of the kernel api */
  906 
  907 void *
  908 agp_find_device(int unit)
  909 {
  910         return device_lookup(&agp_cd, unit);
  911 }
  912 
  913 enum agp_acquire_state
  914 agp_state(void *devcookie)
  915 {
  916         struct agp_softc *sc = devcookie;
  917         return sc->as_state;
  918 }
  919 
  920 void
  921 agp_get_info(void *devcookie, struct agp_info *info)
  922 {
  923         struct agp_softc *sc = devcookie;
  924 
  925         info->ai_mode = pci_conf_read(sc->as_pc, sc->as_tag,
  926             sc->as_capoff + AGP_STATUS);
  927         info->ai_aperture_base = sc->as_apaddr;
  928         info->ai_aperture_size = sc->as_apsize; /* XXXfvdl inconsistent */
  929         info->ai_memory_allowed = sc->as_maxmem;
  930         info->ai_memory_used = sc->as_allocated;
  931 }
  932 
  933 int
  934 agp_acquire(void *dev)
  935 {
  936         return agp_acquire_helper(dev, AGP_ACQUIRE_KERNEL);
  937 }
  938 
  939 int
  940 agp_release(void *dev)
  941 {
  942         return agp_release_helper(dev, AGP_ACQUIRE_KERNEL);
  943 }
  944 
  945 int
  946 agp_enable(void *dev, u_int32_t mode)
  947 {
  948         struct agp_softc *sc = dev;
  949 
  950         return AGP_ENABLE(sc, mode);
  951 }
  952 
  953 void *agp_alloc_memory(void *dev, int type, vsize_t bytes)
  954 {
  955         struct agp_softc *sc = dev;
  956 
  957         return (void *)AGP_ALLOC_MEMORY(sc, type, bytes);
  958 }
  959 
  960 void agp_free_memory(void *dev, void *handle)
  961 {
  962         struct agp_softc *sc = dev;
  963         struct agp_memory *mem = (struct agp_memory *) handle;
  964         AGP_FREE_MEMORY(sc, mem);
  965 }
  966 
  967 int agp_bind_memory(void *dev, void *handle, off_t offset)
  968 {
  969         struct agp_softc *sc = dev;
  970         struct agp_memory *mem = (struct agp_memory *) handle;
  971 
  972         return AGP_BIND_MEMORY(sc, mem, offset);
  973 }
  974 
  975 int agp_unbind_memory(void *dev, void *handle)
  976 {
  977         struct agp_softc *sc = dev;
  978         struct agp_memory *mem = (struct agp_memory *) handle;
  979 
  980         return AGP_UNBIND_MEMORY(sc, mem);
  981 }
  982 
  983 void agp_memory_info(void *dev, void *handle, struct agp_memory_info *mi)
  984 {
  985         struct agp_memory *mem = (struct agp_memory *) handle;
  986 
  987         mi->ami_size = mem->am_size;
  988         mi->ami_physical = mem->am_physical;
  989         mi->ami_offset = mem->am_offset;
  990         mi->ami_is_bound = mem->am_is_bound;
  991 }
  992 
  993 int
  994 agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags,
  995                  bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr,
  996                  bus_dma_segment_t *seg, int nseg, int *rseg)
  997 
  998 {
  999         int error, level = 0;
 1000 
 1001         if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
 1002                         seg, nseg, rseg, BUS_DMA_NOWAIT)) != 0)
 1003                 goto out;
 1004         level++;
 1005 
 1006         if ((error = bus_dmamem_map(tag, seg, *rseg, size, vaddr,
 1007                         BUS_DMA_NOWAIT | flags)) != 0)
 1008                 goto out;
 1009         level++;
 1010 
 1011         if ((error = bus_dmamap_create(tag, size, *rseg, size, 0,
 1012                         BUS_DMA_NOWAIT, mapp)) != 0)
 1013                 goto out;
 1014         level++;
 1015 
 1016         if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL,
 1017                         BUS_DMA_NOWAIT)) != 0)
 1018                 goto out;
 1019 
 1020         *baddr = (*mapp)->dm_segs[0].ds_addr;
 1021 
 1022         return 0;
 1023 out:
 1024         switch (level) {
 1025         case 3:
 1026                 bus_dmamap_destroy(tag, *mapp);
 1027                 /* FALLTHROUGH */
 1028         case 2:
 1029                 bus_dmamem_unmap(tag, *vaddr, size);
 1030                 /* FALLTHROUGH */
 1031         case 1:
 1032                 bus_dmamem_free(tag, seg, *rseg);
 1033                 break;
 1034         default:
 1035                 break;
 1036         }
 1037 
 1038         return error;
 1039 }
 1040 
 1041 void
 1042 agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map,
 1043                 caddr_t vaddr, bus_dma_segment_t *seg, int nseg)
 1044 {
 1045 
 1046         bus_dmamap_unload(tag, map);
 1047         bus_dmamap_destroy(tag, map);
 1048         bus_dmamem_unmap(tag, vaddr, size);
 1049         bus_dmamem_free(tag, seg, nseg);
 1050 }

Cache object: 36916609f8805273cf8bf23613c00c4b


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