linux/drivers/char/agp/efficeon-agp.c
<<
>>
Prefs
   1/*
   2 * Transmeta's Efficeon AGPGART driver.
   3 *
   4 * Based upon a diff by Linus around November '02.
   5 *
   6 * Ported to the 2.6 kernel by Carlos Puchol <cpglinux@puchol.com>
   7 * and H. Peter Anvin <hpa@transmeta.com>.
   8 */
   9
  10/*
  11 * NOTE-cpg-040217:
  12 *
  13 *   - when compiled as a module, after loading the module,
  14 *     it will refuse to unload, indicating it is in use,
  15 *     when it is not.
  16 *   - no s3 (suspend to ram) testing.
  17 *   - tested on the efficeon integrated nothbridge for tens
  18 *     of iterations of starting x and glxgears.
  19 *   - tested with radeon 9000 and radeon mobility m9 cards
  20 *   - tested with c3/c4 enabled (with the mobility m9 card)
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/pci.h>
  25#include <linux/init.h>
  26#include <linux/agp_backend.h>
  27#include <linux/gfp.h>
  28#include <linux/page-flags.h>
  29#include <linux/mm.h>
  30#include "agp.h"
  31
  32/*
  33 * The real differences to the generic AGP code is
  34 * in the GART mappings - a two-level setup with the
  35 * first level being an on-chip 64-entry table.
  36 *
  37 * The page array is filled through the ATTPAGE register
  38 * (Aperture Translation Table Page Register) at 0xB8. Bits:
  39 *  31:20: physical page address
  40 *   11:9: Page Attribute Table Index (PATI)
  41 *         must match the PAT index for the
  42 *         mapped pages (the 2nd level page table pages
  43 *         themselves should be just regular WB-cacheable,
  44 *         so this is normally zero.)
  45 *      8: Present
  46 *    7:6: reserved, write as zero
  47 *    5:0: GATT directory index: which 1st-level entry
  48 *
  49 * The Efficeon AGP spec requires pages to be WB-cacheable
  50 * but to be explicitly CLFLUSH'd after any changes.
  51 */
  52#define EFFICEON_ATTPAGE        0xb8
  53#define EFFICEON_L1_SIZE        64      /* Number of PDE pages */
  54
  55#define EFFICEON_PATI           (0 << 9)
  56#define EFFICEON_PRESENT        (1 << 8)
  57
  58static struct _efficeon_private {
  59        unsigned long l1_table[EFFICEON_L1_SIZE];
  60} efficeon_private;
  61
  62static const struct gatt_mask efficeon_generic_masks[] =
  63{
  64        {.mask = 0x00000001, .type = 0}
  65};
  66
  67/* This function does the same thing as mask_memory() for this chipset... */
  68static inline unsigned long efficeon_mask_memory(struct page *page)
  69{
  70        unsigned long addr = page_to_phys(page);
  71        return addr | 0x00000001;
  72}
  73
  74static const struct aper_size_info_lvl2 efficeon_generic_sizes[4] =
  75{
  76        {256, 65536, 0},
  77        {128, 32768, 32},
  78        {64, 16384, 48},
  79        {32, 8192, 56}
  80};
  81
  82/*
  83 * Control interfaces are largely identical to
  84 * the legacy Intel 440BX..
  85 */
  86
  87static int efficeon_fetch_size(void)
  88{
  89        int i;
  90        u16 temp;
  91        struct aper_size_info_lvl2 *values;
  92
  93        pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp);
  94        values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
  95
  96        for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
  97                if (temp == values[i].size_value) {
  98                        agp_bridge->previous_size =
  99                            agp_bridge->current_size = (void *) (values + i);
 100                        agp_bridge->aperture_size_idx = i;
 101                        return values[i].size;
 102                }
 103        }
 104
 105        return 0;
 106}
 107
 108static void efficeon_tlbflush(struct agp_memory * mem)
 109{
 110        printk(KERN_DEBUG PFX "efficeon_tlbflush()\n");
 111        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2200);
 112        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
 113}
 114
 115static void efficeon_cleanup(void)
 116{
 117        u16 temp;
 118        struct aper_size_info_lvl2 *previous_size;
 119
 120        printk(KERN_DEBUG PFX "efficeon_cleanup()\n");
 121        previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
 122        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
 123        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
 124        pci_write_config_word(agp_bridge->dev, INTEL_APSIZE,
 125                              previous_size->size_value);
 126}
 127
 128static int efficeon_configure(void)
 129{
 130        u32 temp;
 131        u16 temp2;
 132        struct aper_size_info_lvl2 *current_size;
 133
 134        printk(KERN_DEBUG PFX "efficeon_configure()\n");
 135
 136        current_size = A_SIZE_LVL2(agp_bridge->current_size);
 137
 138        /* aperture size */
 139        pci_write_config_word(agp_bridge->dev, INTEL_APSIZE,
 140                              current_size->size_value);
 141
 142        /* address to map to */
 143        pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
 144        agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 145
 146        /* agpctrl */
 147        pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
 148
 149        /* paccfg/nbxcfg */
 150        pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
 151        pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG,
 152                              (temp2 & ~(1 << 10)) | (1 << 9) | (1 << 11));
 153        /* clear any possible error conditions */
 154        pci_write_config_byte(agp_bridge->dev, INTEL_ERRSTS + 1, 7);
 155        return 0;
 156}
 157
 158static int efficeon_free_gatt_table(struct agp_bridge_data *bridge)
 159{
 160        int index, freed = 0;
 161
 162        for (index = 0; index < EFFICEON_L1_SIZE; index++) {
 163                unsigned long page = efficeon_private.l1_table[index];
 164                if (page) {
 165                        efficeon_private.l1_table[index] = 0;
 166                        ClearPageReserved(virt_to_page((char *)page));
 167                        free_page(page);
 168                        freed++;
 169                }
 170                printk(KERN_DEBUG PFX "efficeon_free_gatt_table(%p, %02x, %08x)\n",
 171                        agp_bridge->dev, EFFICEON_ATTPAGE, index);
 172                pci_write_config_dword(agp_bridge->dev,
 173                        EFFICEON_ATTPAGE, index);
 174        }
 175        printk(KERN_DEBUG PFX "efficeon_free_gatt_table() freed %d pages\n", freed);
 176        return 0;
 177}
 178
 179
 180/*
 181 * Since we don't need contiguous memory we just try
 182 * to get the gatt table once
 183 */
 184
 185#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 186#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
 187        GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
 188#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
 189#undef  GET_GATT
 190#define GET_GATT(addr) (efficeon_private.gatt_pages[\
 191        GET_PAGE_DIR_IDX(addr)]->remapped)
 192
 193static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
 194{
 195        int index;
 196        const int pati    = EFFICEON_PATI;
 197        const int present = EFFICEON_PRESENT;
 198        const int clflush_chunk = ((cpuid_ebx(1) >> 8) & 0xff) << 3;
 199        int num_entries, l1_pages;
 200
 201        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 202
 203        printk(KERN_DEBUG PFX "efficeon_create_gatt_table(%d)\n", num_entries);
 204
 205        /* There are 2^10 PTE pages per PDE page */
 206        BUG_ON(num_entries & 0x3ff);
 207        l1_pages = num_entries >> 10;
 208
 209        for (index = 0 ; index < l1_pages ; index++) {
 210                int offset;
 211                unsigned long page;
 212                unsigned long value;
 213
 214                page = efficeon_private.l1_table[index];
 215                BUG_ON(page);
 216
 217                page = get_zeroed_page(GFP_KERNEL);
 218                if (!page) {
 219                        efficeon_free_gatt_table(agp_bridge);
 220                        return -ENOMEM;
 221                }
 222                SetPageReserved(virt_to_page((char *)page));
 223
 224                for (offset = 0; offset < PAGE_SIZE; offset += clflush_chunk)
 225                        clflush((char *)page+offset);
 226
 227                efficeon_private.l1_table[index] = page;
 228
 229                value = virt_to_phys((unsigned long *)page) | pati | present | index;
 230
 231                pci_write_config_dword(agp_bridge->dev,
 232                        EFFICEON_ATTPAGE, value);
 233        }
 234
 235        return 0;
 236}
 237
 238static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
 239{
 240        int i, count = mem->page_count, num_entries;
 241        unsigned int *page, *last_page;
 242        const int clflush_chunk = ((cpuid_ebx(1) >> 8) & 0xff) << 3;
 243        const unsigned long clflush_mask = ~(clflush_chunk-1);
 244
 245        printk(KERN_DEBUG PFX "efficeon_insert_memory(%lx, %d)\n", pg_start, count);
 246
 247        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 248        if ((pg_start + mem->page_count) > num_entries)
 249                return -EINVAL;
 250        if (type != 0 || mem->type != 0)
 251                return -EINVAL;
 252
 253        if (!mem->is_flushed) {
 254                global_cache_flush();
 255                mem->is_flushed = true;
 256        }
 257
 258        last_page = NULL;
 259        for (i = 0; i < count; i++) {
 260                int index = pg_start + i;
 261                unsigned long insert = efficeon_mask_memory(mem->pages[i]);
 262
 263                page = (unsigned int *) efficeon_private.l1_table[index >> 10];
 264
 265                if (!page)
 266                        continue;
 267
 268                page += (index & 0x3ff);
 269                *page = insert;
 270
 271                /* clflush is slow, so don't clflush until we have to */
 272                if (last_page &&
 273                    (((unsigned long)page^(unsigned long)last_page) &
 274                     clflush_mask))
 275                        clflush(last_page);
 276
 277                last_page = page;
 278        }
 279
 280        if ( last_page )
 281                clflush(last_page);
 282
 283        agp_bridge->driver->tlb_flush(mem);
 284        return 0;
 285}
 286
 287static int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int type)
 288{
 289        int i, count = mem->page_count, num_entries;
 290
 291        printk(KERN_DEBUG PFX "efficeon_remove_memory(%lx, %d)\n", pg_start, count);
 292
 293        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 294
 295        if ((pg_start + mem->page_count) > num_entries)
 296                return -EINVAL;
 297        if (type != 0 || mem->type != 0)
 298                return -EINVAL;
 299
 300        for (i = 0; i < count; i++) {
 301                int index = pg_start + i;
 302                unsigned int *page = (unsigned int *) efficeon_private.l1_table[index >> 10];
 303
 304                if (!page)
 305                        continue;
 306                page += (index & 0x3ff);
 307                *page = 0;
 308        }
 309        agp_bridge->driver->tlb_flush(mem);
 310        return 0;
 311}
 312
 313
 314static const struct agp_bridge_driver efficeon_driver = {
 315        .owner                  = THIS_MODULE,
 316        .aperture_sizes         = efficeon_generic_sizes,
 317        .size_type              = LVL2_APER_SIZE,
 318        .num_aperture_sizes     = 4,
 319        .configure              = efficeon_configure,
 320        .fetch_size             = efficeon_fetch_size,
 321        .cleanup                = efficeon_cleanup,
 322        .tlb_flush              = efficeon_tlbflush,
 323        .mask_memory            = agp_generic_mask_memory,
 324        .masks                  = efficeon_generic_masks,
 325        .agp_enable             = agp_generic_enable,
 326        .cache_flush            = global_cache_flush,
 327
 328        // Efficeon-specific GATT table setup / populate / teardown
 329        .create_gatt_table      = efficeon_create_gatt_table,
 330        .free_gatt_table        = efficeon_free_gatt_table,
 331        .insert_memory          = efficeon_insert_memory,
 332        .remove_memory          = efficeon_remove_memory,
 333        .cant_use_aperture      = false,        // true might be faster?
 334
 335        // Generic
 336        .alloc_by_type          = agp_generic_alloc_by_type,
 337        .free_by_type           = agp_generic_free_by_type,
 338        .agp_alloc_page         = agp_generic_alloc_page,
 339        .agp_alloc_pages        = agp_generic_alloc_pages,
 340        .agp_destroy_page       = agp_generic_destroy_page,
 341        .agp_destroy_pages      = agp_generic_destroy_pages,
 342        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 343};
 344
 345static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
 346                                     const struct pci_device_id *ent)
 347{
 348        struct agp_bridge_data *bridge;
 349        u8 cap_ptr;
 350        struct resource *r;
 351
 352        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 353        if (!cap_ptr)
 354                return -ENODEV;
 355
 356        /* Probe for Efficeon controller */
 357        if (pdev->device != PCI_DEVICE_ID_EFFICEON) {
 358                printk(KERN_ERR PFX "Unsupported Efficeon chipset (device id: %04x)\n",
 359                    pdev->device);
 360                return -ENODEV;
 361        }
 362
 363        printk(KERN_INFO PFX "Detected Transmeta Efficeon TM8000 series chipset\n");
 364
 365        bridge = agp_alloc_bridge();
 366        if (!bridge)
 367                return -ENOMEM;
 368
 369        bridge->driver = &efficeon_driver;
 370        bridge->dev = pdev;
 371        bridge->capndx = cap_ptr;
 372
 373        /*
 374        * The following fixes the case where the BIOS has "forgotten" to
 375        * provide an address range for the GART.
 376        * 20030610 - hamish@zot.org
 377        */
 378        r = &pdev->resource[0];
 379        if (!r->start && r->end) {
 380                if (pci_assign_resource(pdev, 0)) {
 381                        printk(KERN_ERR PFX "could not assign resource 0\n");
 382                        agp_put_bridge(bridge);
 383                        return -ENODEV;
 384                }
 385        }
 386
 387        /*
 388        * If the device has not been properly setup, the following will catch
 389        * the problem and should stop the system from crashing.
 390        * 20030610 - hamish@zot.org
 391        */
 392        if (pci_enable_device(pdev)) {
 393                printk(KERN_ERR PFX "Unable to Enable PCI device\n");
 394                agp_put_bridge(bridge);
 395                return -ENODEV;
 396        }
 397
 398        /* Fill in the mode register */
 399        if (cap_ptr) {
 400                pci_read_config_dword(pdev,
 401                                bridge->capndx+PCI_AGP_STATUS,
 402                                &bridge->mode);
 403        }
 404
 405        pci_set_drvdata(pdev, bridge);
 406        return agp_add_bridge(bridge);
 407}
 408
 409static void __devexit agp_efficeon_remove(struct pci_dev *pdev)
 410{
 411        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 412
 413        agp_remove_bridge(bridge);
 414        agp_put_bridge(bridge);
 415}
 416
 417#ifdef CONFIG_PM
 418static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state)
 419{
 420        return 0;
 421}
 422
 423static int agp_efficeon_resume(struct pci_dev *pdev)
 424{
 425        printk(KERN_DEBUG PFX "agp_efficeon_resume()\n");
 426        return efficeon_configure();
 427}
 428#endif
 429
 430static struct pci_device_id agp_efficeon_pci_table[] = {
 431        {
 432        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
 433        .class_mask     = ~0,
 434        .vendor         = PCI_VENDOR_ID_TRANSMETA,
 435        .device         = PCI_ANY_ID,
 436        .subvendor      = PCI_ANY_ID,
 437        .subdevice      = PCI_ANY_ID,
 438        },
 439        { }
 440};
 441
 442MODULE_DEVICE_TABLE(pci, agp_efficeon_pci_table);
 443
 444static struct pci_driver agp_efficeon_pci_driver = {
 445        .name           = "agpgart-efficeon",
 446        .id_table       = agp_efficeon_pci_table,
 447        .probe          = agp_efficeon_probe,
 448        .remove         = agp_efficeon_remove,
 449#ifdef CONFIG_PM
 450        .suspend        = agp_efficeon_suspend,
 451        .resume         = agp_efficeon_resume,
 452#endif
 453};
 454
 455static int __init agp_efficeon_init(void)
 456{
 457        static int agp_initialised=0;
 458
 459        if (agp_off)
 460                return -EINVAL;
 461
 462        if (agp_initialised == 1)
 463                return 0;
 464        agp_initialised=1;
 465
 466        return pci_register_driver(&agp_efficeon_pci_driver);
 467}
 468
 469static void __exit agp_efficeon_cleanup(void)
 470{
 471        pci_unregister_driver(&agp_efficeon_pci_driver);
 472}
 473
 474module_init(agp_efficeon_init);
 475module_exit(agp_efficeon_cleanup);
 476
 477MODULE_AUTHOR("Carlos Puchol <cpglinux@puchol.com>");
 478MODULE_LICENSE("GPL and additional rights");
 479