linux/drivers/char/agp/sgi-agp.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2003-2005 Silicon Graphics, Inc.  All Rights Reserved.
   7 */
   8
   9/*
  10 * SGI TIOCA AGPGART routines.
  11 *
  12 */
  13
  14#include <linux/acpi.h>
  15#include <linux/module.h>
  16#include <linux/pci.h>
  17#include <linux/slab.h>
  18#include <linux/agp_backend.h>
  19#include <asm/sn/addrs.h>
  20#include <asm/sn/io.h>
  21#include <asm/sn/pcidev.h>
  22#include <asm/sn/pcibus_provider_defs.h>
  23#include <asm/sn/tioca_provider.h>
  24#include "agp.h"
  25
  26extern int agp_memory_reserved;
  27extern uint32_t tioca_gart_found;
  28extern struct list_head tioca_list;
  29static struct agp_bridge_data **sgi_tioca_agp_bridges;
  30
  31/*
  32 * The aperature size and related information is set up at TIOCA init time.
  33 * Values for this table will be extracted and filled in at
  34 * sgi_tioca_fetch_size() time.
  35 */
  36
  37static struct aper_size_info_fixed sgi_tioca_sizes[] = {
  38        {0, 0, 0},
  39};
  40
  41static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
  42{
  43        struct page *page;
  44        int nid;
  45        struct tioca_kernel *info =
  46            (struct tioca_kernel *)bridge->dev_private_data;
  47
  48        nid = info->ca_closest_node;
  49        page = alloc_pages_node(nid, GFP_KERNEL, 0);
  50        if (!page)
  51                return NULL;
  52
  53        get_page(page);
  54        atomic_inc(&agp_bridge->current_memory_agp);
  55        return page;
  56}
  57
  58/*
  59 * Flush GART tlb's.  Cannot selectively flush based on memory so the mem
  60 * arg is ignored.
  61 */
  62
  63static void sgi_tioca_tlbflush(struct agp_memory *mem)
  64{
  65        tioca_tlbflush(mem->bridge->dev_private_data);
  66}
  67
  68/*
  69 * Given an address of a host physical page, turn it into a valid gart
  70 * entry.
  71 */
  72static unsigned long
  73sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
  74                      int type)
  75{
  76        return tioca_physpage_to_gart(addr);
  77}
  78
  79static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
  80{
  81        tioca_fastwrite_enable(bridge->dev_private_data);
  82}
  83
  84/*
  85 * sgi_tioca_configure() doesn't have anything to do since the base CA driver
  86 * has alreay set up the GART.
  87 */
  88
  89static int sgi_tioca_configure(void)
  90{
  91        return 0;
  92}
  93
  94/*
  95 * Determine gfx aperature size.  This has already been determined by the
  96 * CA driver init, so just need to set agp_bridge values accordingly.
  97 */
  98
  99static int sgi_tioca_fetch_size(void)
 100{
 101        struct tioca_kernel *info =
 102            (struct tioca_kernel *)agp_bridge->dev_private_data;
 103
 104        sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
 105        sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
 106
 107        return sgi_tioca_sizes[0].size;
 108}
 109
 110static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
 111{
 112        struct tioca_kernel *info =
 113            (struct tioca_kernel *)bridge->dev_private_data;
 114
 115        bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
 116        bridge->gatt_table = bridge->gatt_table_real;
 117        bridge->gatt_bus_addr = info->ca_gfxgart_base;
 118
 119        return 0;
 120}
 121
 122static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
 123{
 124        return 0;
 125}
 126
 127static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
 128                                   int type)
 129{
 130        int num_entries;
 131        size_t i;
 132        off_t j;
 133        void *temp;
 134        struct agp_bridge_data *bridge;
 135        u64 *table;
 136
 137        bridge = mem->bridge;
 138        if (!bridge)
 139                return -EINVAL;
 140
 141        table = (u64 *)bridge->gatt_table;
 142
 143        temp = bridge->current_size;
 144
 145        switch (bridge->driver->size_type) {
 146        case U8_APER_SIZE:
 147                num_entries = A_SIZE_8(temp)->num_entries;
 148                break;
 149        case U16_APER_SIZE:
 150                num_entries = A_SIZE_16(temp)->num_entries;
 151                break;
 152        case U32_APER_SIZE:
 153                num_entries = A_SIZE_32(temp)->num_entries;
 154                break;
 155        case FIXED_APER_SIZE:
 156                num_entries = A_SIZE_FIX(temp)->num_entries;
 157                break;
 158        case LVL2_APER_SIZE:
 159                return -EINVAL;
 160        default:
 161                num_entries = 0;
 162                break;
 163        }
 164
 165        num_entries -= agp_memory_reserved / PAGE_SIZE;
 166        if (num_entries < 0)
 167                num_entries = 0;
 168
 169        if (type != 0 || mem->type != 0) {
 170                return -EINVAL;
 171        }
 172
 173        if ((pg_start + mem->page_count) > num_entries)
 174                return -EINVAL;
 175
 176        j = pg_start;
 177
 178        while (j < (pg_start + mem->page_count)) {
 179                if (table[j])
 180                        return -EBUSY;
 181                j++;
 182        }
 183
 184        if (!mem->is_flushed) {
 185                bridge->driver->cache_flush();
 186                mem->is_flushed = true;
 187        }
 188
 189        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 190                table[j] =
 191                    bridge->driver->mask_memory(bridge,
 192                                                page_to_phys(mem->pages[i]),
 193                                                mem->type);
 194        }
 195
 196        bridge->driver->tlb_flush(mem);
 197        return 0;
 198}
 199
 200static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
 201                                   int type)
 202{
 203        size_t i;
 204        struct agp_bridge_data *bridge;
 205        u64 *table;
 206
 207        bridge = mem->bridge;
 208        if (!bridge)
 209                return -EINVAL;
 210
 211        if (type != 0 || mem->type != 0) {
 212                return -EINVAL;
 213        }
 214
 215        table = (u64 *)bridge->gatt_table;
 216
 217        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 218                table[i] = 0;
 219        }
 220
 221        bridge->driver->tlb_flush(mem);
 222        return 0;
 223}
 224
 225static void sgi_tioca_cache_flush(void)
 226{
 227}
 228
 229/*
 230 * Cleanup.  Nothing to do as the CA driver owns the GART.
 231 */
 232
 233static void sgi_tioca_cleanup(void)
 234{
 235}
 236
 237static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
 238{
 239        struct agp_bridge_data *bridge;
 240
 241        list_for_each_entry(bridge, &agp_bridges, list) {
 242                if (bridge->dev->bus == pdev->bus)
 243                        break;
 244        }
 245        return bridge;
 246}
 247
 248const struct agp_bridge_driver sgi_tioca_driver = {
 249        .owner = THIS_MODULE,
 250        .size_type = U16_APER_SIZE,
 251        .configure = sgi_tioca_configure,
 252        .fetch_size = sgi_tioca_fetch_size,
 253        .cleanup = sgi_tioca_cleanup,
 254        .tlb_flush = sgi_tioca_tlbflush,
 255        .mask_memory = sgi_tioca_mask_memory,
 256        .agp_enable = sgi_tioca_agp_enable,
 257        .cache_flush = sgi_tioca_cache_flush,
 258        .create_gatt_table = sgi_tioca_create_gatt_table,
 259        .free_gatt_table = sgi_tioca_free_gatt_table,
 260        .insert_memory = sgi_tioca_insert_memory,
 261        .remove_memory = sgi_tioca_remove_memory,
 262        .alloc_by_type = agp_generic_alloc_by_type,
 263        .free_by_type = agp_generic_free_by_type,
 264        .agp_alloc_page = sgi_tioca_alloc_page,
 265        .agp_destroy_page = agp_generic_destroy_page,
 266        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 267        .cant_use_aperture = true,
 268        .needs_scratch_page = false,
 269        .num_aperture_sizes = 1,
 270};
 271
 272static int agp_sgi_init(void)
 273{
 274        unsigned int j;
 275        struct tioca_kernel *info;
 276        struct pci_dev *pdev = NULL;
 277
 278        if (tioca_gart_found)
 279                printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
 280        else
 281                return 0;
 282
 283        sgi_tioca_agp_bridges = kmalloc_array(tioca_gart_found,
 284                                              sizeof(struct agp_bridge_data *),
 285                                              GFP_KERNEL);
 286        if (!sgi_tioca_agp_bridges)
 287                return -ENOMEM;
 288
 289        j = 0;
 290        list_for_each_entry(info, &tioca_list, ca_list) {
 291                if (list_empty(info->ca_devices))
 292                        continue;
 293                list_for_each_entry(pdev, info->ca_devices, bus_list) {
 294                        u8 cap_ptr;
 295
 296                        if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
 297                                continue;
 298                        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 299                        if (!cap_ptr)
 300                                continue;
 301                }
 302                sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
 303                printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
 304                       sgi_tioca_agp_bridges[j]);
 305                if (sgi_tioca_agp_bridges[j]) {
 306                        sgi_tioca_agp_bridges[j]->dev = pdev;
 307                        sgi_tioca_agp_bridges[j]->dev_private_data = info;
 308                        sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
 309                        sgi_tioca_agp_bridges[j]->gart_bus_addr =
 310                            info->ca_gfxap_base;
 311                        sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */
 312                            (0x1 << 9) |        /* SBA supported */
 313                            (0x1 << 5) |        /* 64-bit addresses supported */
 314                            (0x1 << 4) |        /* FW supported */
 315                            (0x1 << 3) |        /* AGP 3.0 mode */
 316                            0x2;        /* 8x transfer only */
 317                        sgi_tioca_agp_bridges[j]->current_size =
 318                            sgi_tioca_agp_bridges[j]->previous_size =
 319                            (void *)&sgi_tioca_sizes[0];
 320                        agp_add_bridge(sgi_tioca_agp_bridges[j]);
 321                }
 322                j++;
 323        }
 324
 325        agp_find_bridge = &sgi_tioca_find_bridge;
 326        return 0;
 327}
 328
 329static void agp_sgi_cleanup(void)
 330{
 331        kfree(sgi_tioca_agp_bridges);
 332        sgi_tioca_agp_bridges = NULL;
 333}
 334
 335module_init(agp_sgi_init);
 336module_exit(agp_sgi_cleanup);
 337
 338MODULE_LICENSE("GPL and additional rights");
 339