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/agp/agp_amd.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 (c) 2000 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *      $FreeBSD: src/sys/dev/agp/agp_amd.c,v 1.25 2007/11/12 21:51:36 jhb Exp $
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/malloc.h>
   32 #include <sys/kernel.h>
   33 #include <sys/bus.h>
   34 #include <sys/lock.h>
   35 #include <sys/rman.h>
   36 
   37 #include <bus/pci/pcivar.h>
   38 #include <bus/pci/pcireg.h>
   39 #include "agppriv.h"
   40 #include "agpreg.h"
   41 
   42 #include <vm/vm.h>
   43 #include <vm/vm_object.h>
   44 #include <vm/pmap.h>
   45 
   46 MALLOC_DECLARE(M_AGP);
   47 
   48 #define READ2(off)      bus_space_read_2(sc->bst, sc->bsh, off)
   49 #define READ4(off)      bus_space_read_4(sc->bst, sc->bsh, off)
   50 #define WRITE2(off,v)   bus_space_write_2(sc->bst, sc->bsh, off, v)
   51 #define WRITE4(off,v)   bus_space_write_4(sc->bst, sc->bsh, off, v)
   52 
   53 struct agp_amd_gatt {
   54         u_int32_t       ag_entries;
   55         u_int32_t      *ag_virtual;     /* virtual address of gatt */
   56         vm_offset_t     ag_physical;
   57         u_int32_t      *ag_vdir;        /* virtual address of page dir */
   58         vm_offset_t     ag_pdir;        /* physical address of page dir */
   59 };
   60 
   61 struct agp_amd_softc {
   62         struct agp_softc        agp;
   63         struct resource        *regs;   /* memory mapped control registers */
   64         bus_space_tag_t         bst;    /* bus_space tag */
   65         bus_space_handle_t      bsh;    /* bus_space handle */
   66         u_int32_t               initial_aperture; /* aperture size at startup */
   67         struct agp_amd_gatt    *gatt;
   68 };
   69 
   70 static struct agp_amd_gatt *
   71 agp_amd_alloc_gatt(device_t dev)
   72 {
   73         u_int32_t apsize = AGP_GET_APERTURE(dev);
   74         u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
   75         struct agp_amd_gatt *gatt;
   76         int i, npages, pdir_offset;
   77 
   78         if (bootverbose)
   79                 device_printf(dev,
   80                               "allocating GATT for aperture of size %dM\n",
   81                               apsize / (1024*1024));
   82 
   83         gatt = kmalloc(sizeof(struct agp_amd_gatt), M_AGP, M_INTWAIT);
   84 
   85         /*
   86          * The AMD751 uses a page directory to map a non-contiguous
   87          * gatt so we don't need to use contigmalloc.
   88          * Malloc individual gatt pages and map them into the page
   89          * directory.
   90          */
   91         gatt->ag_entries = entries;
   92         gatt->ag_virtual = kmalloc(entries * sizeof(u_int32_t),
   93                                   M_AGP, M_INTWAIT | M_ZERO);
   94 
   95         /*
   96          * Allocate the page directory.
   97          */
   98         gatt->ag_vdir = kmalloc(AGP_PAGE_SIZE, M_AGP, M_INTWAIT | M_ZERO);
   99 
  100         gatt->ag_pdir = vtophys((vm_offset_t) gatt->ag_vdir);
  101         if(bootverbose)
  102                 device_printf(dev, "gatt -> ag_pdir %#lx\n",
  103                     (u_long)gatt->ag_pdir);
  104         /*
  105          * Allocate the gatt pages
  106          */
  107         gatt->ag_entries = entries;
  108         if(bootverbose)
  109                 device_printf(dev, "allocating GATT for %d AGP page entries\n", 
  110                         gatt->ag_entries);
  111 
  112         gatt->ag_physical = vtophys((vm_offset_t) gatt->ag_virtual);
  113 
  114         /*
  115          * Map the pages of the GATT into the page directory.
  116          *
  117          * The GATT page addresses are mapped into the directory offset by
  118          * an amount dependent on the base address of the aperture. This
  119          * is and offset into the page directory, not an offset added to
  120          * the addresses of the gatt pages.
  121          */
  122 
  123         pdir_offset = pci_read_config(dev, AGP_AMD751_APBASE, 4) >> 22;
  124 
  125         npages = ((entries * sizeof(u_int32_t) + AGP_PAGE_SIZE - 1)
  126                   >> AGP_PAGE_SHIFT);
  127 
  128         for (i = 0; i < npages; i++) {
  129                 vm_offset_t va;
  130                 vm_offset_t pa;
  131 
  132                 va = ((vm_offset_t) gatt->ag_virtual) + i * AGP_PAGE_SIZE;
  133                 pa = vtophys(va);
  134                 gatt->ag_vdir[i + pdir_offset] = pa | 1;
  135         }
  136 
  137         /*
  138          * Make sure the chipset can see everything.
  139          */
  140         agp_flush_cache();
  141 
  142         return gatt;
  143 }
  144 
  145 static void
  146 agp_amd_free_gatt(struct agp_amd_gatt *gatt)
  147 {
  148         kfree(gatt->ag_virtual, M_AGP);
  149         kfree(gatt->ag_vdir, M_AGP);
  150         kfree(gatt, M_AGP);
  151 }
  152 
  153 static const char*
  154 agp_amd_match(device_t dev)
  155 {
  156         if (pci_get_class(dev) != PCIC_BRIDGE
  157             || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
  158                 return NULL;
  159 
  160         if (agp_find_caps(dev) == 0)
  161                 return NULL;
  162 
  163         switch (pci_get_devid(dev)) {
  164         case 0x70061022:
  165                 return ("AMD 751 host to AGP bridge");
  166         case 0x700e1022:
  167                 return ("AMD 761 host to AGP bridge");
  168         case 0x700c1022:
  169                 return ("AMD 762 host to AGP bridge");
  170         };
  171 
  172         return NULL;
  173 }
  174 
  175 static int
  176 agp_amd_probe(device_t dev)
  177 {
  178         const char *desc;
  179 
  180         if (resource_disabled("agp", device_get_unit(dev)))
  181                 return (ENXIO);
  182         desc = agp_amd_match(dev);
  183         if (desc) {
  184                 device_verbose(dev);
  185                 device_set_desc(dev, desc);
  186                 return BUS_PROBE_DEFAULT;
  187         }
  188 
  189         return ENXIO;
  190 }
  191 
  192 static int
  193 agp_amd_attach(device_t dev)
  194 {
  195         struct agp_amd_softc *sc = device_get_softc(dev);
  196         struct agp_amd_gatt *gatt;
  197         int error, rid;
  198 
  199         error = agp_generic_attach(dev);
  200         if (error)
  201                 return error;
  202 
  203         rid = AGP_AMD751_REGISTERS;
  204         sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  205                                           RF_ACTIVE);
  206         if (!sc->regs) {
  207                 agp_generic_detach(dev);
  208                 return ENOMEM;
  209         }
  210 
  211         sc->bst = rman_get_bustag(sc->regs);
  212         sc->bsh = rman_get_bushandle(sc->regs);
  213 
  214         sc->initial_aperture = AGP_GET_APERTURE(dev);
  215         if (sc->initial_aperture == 0) {
  216                 device_printf(dev, "bad initial aperture size, disabling\n");
  217                 return ENXIO;
  218         }
  219 
  220         for (;;) {
  221                 gatt = agp_amd_alloc_gatt(dev);
  222                 if (gatt)
  223                         break;
  224 
  225                 /*
  226                  * Probably contigmalloc failure. Try reducing the
  227                  * aperture so that the gatt size reduces.
  228                  */
  229                 if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
  230                         return ENOMEM;
  231         }
  232         sc->gatt = gatt;
  233 
  234         /* Install the gatt. */
  235         WRITE4(AGP_AMD751_ATTBASE, gatt->ag_pdir);
  236         
  237         /* Enable synchronisation between host and agp. */
  238         pci_write_config(dev,
  239                          AGP_AMD751_MODECTRL,
  240                          AGP_AMD751_MODECTRL_SYNEN, 1);
  241 
  242         /* Set indexing mode for two-level and enable page dir cache */
  243         pci_write_config(dev,
  244                          AGP_AMD751_MODECTRL2,
  245                          AGP_AMD751_MODECTRL2_GPDCE, 1);
  246 
  247         /* Enable the TLB and flush */
  248         WRITE2(AGP_AMD751_STATUS,
  249                READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE);
  250         AGP_FLUSH_TLB(dev);
  251 
  252         return 0;
  253 }
  254 
  255 static int
  256 agp_amd_detach(device_t dev)
  257 {
  258         struct agp_amd_softc *sc = device_get_softc(dev);
  259 
  260         agp_free_cdev(dev);
  261 
  262         /* Disable the TLB.. */
  263         WRITE2(AGP_AMD751_STATUS,
  264                READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE);
  265         
  266         /* Disable host-agp sync */
  267         pci_write_config(dev, AGP_AMD751_MODECTRL, 0x00, 1);
  268         
  269         /* Clear the GATT base */
  270         WRITE4(AGP_AMD751_ATTBASE, 0);
  271 
  272         /* Put the aperture back the way it started. */
  273         AGP_SET_APERTURE(dev, sc->initial_aperture);
  274 
  275         agp_amd_free_gatt(sc->gatt);
  276         agp_free_res(dev);
  277 
  278         bus_release_resource(dev, SYS_RES_MEMORY,
  279                              AGP_AMD751_REGISTERS, sc->regs);
  280 
  281         return 0;
  282 }
  283 
  284 static u_int32_t
  285 agp_amd_get_aperture(device_t dev)
  286 {
  287         int vas;
  288 
  289         /*
  290          * The aperture size is equal to 32M<<vas.
  291          */
  292         vas = (pci_read_config(dev, AGP_AMD751_APCTRL, 1) & 0x06) >> 1;
  293         return (32*1024*1024) << vas;
  294 }
  295 
  296 static int
  297 agp_amd_set_aperture(device_t dev, u_int32_t aperture)
  298 {
  299         int vas;
  300 
  301         /*
  302          * Check for a power of two and make sure its within the
  303          * programmable range.
  304          */
  305         if (aperture & (aperture - 1)
  306             || aperture < 32*1024*1024
  307             || aperture > 2U*1024*1024*1024)
  308                 return EINVAL;
  309 
  310         vas = ffs(aperture / 32*1024*1024) - 1;
  311         
  312         /* 
  313          * While the size register is bits 1-3 of APCTRL, bit 0 must be
  314          * set for the size value to be 'valid'
  315          */
  316         pci_write_config(dev, AGP_AMD751_APCTRL,
  317                          (((pci_read_config(dev, AGP_AMD751_APCTRL, 1) & ~0x06)
  318                           | ((vas << 1) | 1))), 1);
  319 
  320         return 0;
  321 }
  322 
  323 static int
  324 agp_amd_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
  325 {
  326         struct agp_amd_softc *sc = device_get_softc(dev);
  327 
  328         if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
  329                 return EINVAL;
  330 
  331         sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
  332 
  333         /* invalidate the cache */
  334         AGP_FLUSH_TLB(dev);
  335         return 0;
  336 }
  337 
  338 static int
  339 agp_amd_unbind_page(device_t dev, vm_offset_t offset)
  340 {
  341         struct agp_amd_softc *sc = device_get_softc(dev);
  342 
  343         if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
  344                 return EINVAL;
  345 
  346         sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
  347         return 0;
  348 }
  349 
  350 static void
  351 agp_amd_flush_tlb(device_t dev)
  352 {
  353         struct agp_amd_softc *sc = device_get_softc(dev);
  354 
  355         /* Set the cache invalidate bit and wait for the chipset to clear */
  356         WRITE4(AGP_AMD751_TLBCTRL, 1);
  357         do {
  358                 DELAY(1);
  359         } while (READ4(AGP_AMD751_TLBCTRL));
  360 }
  361 
  362 static device_method_t agp_amd_methods[] = {
  363         /* Device interface */
  364         DEVMETHOD(device_probe,         agp_amd_probe),
  365         DEVMETHOD(device_attach,        agp_amd_attach),
  366         DEVMETHOD(device_detach,        agp_amd_detach),
  367         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  368         DEVMETHOD(device_suspend,       bus_generic_suspend),
  369         DEVMETHOD(device_resume,        bus_generic_resume),
  370 
  371         /* AGP interface */
  372         DEVMETHOD(agp_get_aperture,     agp_amd_get_aperture),
  373         DEVMETHOD(agp_set_aperture,     agp_amd_set_aperture),
  374         DEVMETHOD(agp_bind_page,        agp_amd_bind_page),
  375         DEVMETHOD(agp_unbind_page,      agp_amd_unbind_page),
  376         DEVMETHOD(agp_flush_tlb,        agp_amd_flush_tlb),
  377         DEVMETHOD(agp_enable,           agp_generic_enable),
  378         DEVMETHOD(agp_alloc_memory,     agp_generic_alloc_memory),
  379         DEVMETHOD(agp_free_memory,      agp_generic_free_memory),
  380         DEVMETHOD(agp_bind_memory,      agp_generic_bind_memory),
  381         DEVMETHOD(agp_unbind_memory,    agp_generic_unbind_memory),
  382 
  383         DEVMETHOD_END
  384 };
  385 
  386 static driver_t agp_amd_driver = {
  387         "agp",
  388         agp_amd_methods,
  389         sizeof(struct agp_amd_softc),
  390 };
  391 
  392 static devclass_t agp_devclass;
  393 
  394 DRIVER_MODULE(agp_amd, pci, agp_amd_driver, agp_devclass, NULL, NULL);
  395 MODULE_DEPEND(agp_amd, agp, 1, 1, 1);
  396 MODULE_DEPEND(agp_amd, pci, 1, 1, 1);

Cache object: 1116d1829c9a31683e4bed634ae0de31


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