linux/drivers/char/agp/parisc-agp.c
<<
>>
Prefs
   1/*
   2 * HP Quicksilver AGP GART routines
   3 *
   4 * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
   5 *
   6 * Based on drivers/char/agpgart/hp-agp.c which is
   7 * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
   8 *      Bjorn Helgaas <bjorn.helgaas@hp.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 *
  14 */
  15
  16#include <linux/module.h>
  17#include <linux/pci.h>
  18#include <linux/init.h>
  19#include <linux/klist.h>
  20#include <linux/agp_backend.h>
  21#include <linux/log2.h>
  22
  23#include <asm/parisc-device.h>
  24#include <asm/ropes.h>
  25
  26#include "agp.h"
  27
  28#define DRVNAME "quicksilver"
  29#define DRVPFX  DRVNAME ": "
  30
  31#define AGP8X_MODE_BIT          3
  32#define AGP8X_MODE              (1 << AGP8X_MODE_BIT)
  33
  34static unsigned long
  35parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
  36                       int type);
  37
  38static struct _parisc_agp_info {
  39        void __iomem *ioc_regs;
  40        void __iomem *lba_regs;
  41
  42        int lba_cap_offset;
  43
  44        u64 *gatt;
  45        u64 gatt_entries;
  46
  47        u64 gart_base;
  48        u64 gart_size;
  49
  50        int io_page_size;
  51        int io_pages_per_kpage;
  52} parisc_agp_info;
  53
  54static struct gatt_mask parisc_agp_masks[] =
  55{
  56        {
  57                .mask = SBA_PDIR_VALID_BIT,
  58                .type = 0
  59        }
  60};
  61
  62static struct aper_size_info_fixed parisc_agp_sizes[] =
  63{
  64        {0, 0, 0},              /* filled in by parisc_agp_fetch_size() */
  65};
  66
  67static int
  68parisc_agp_fetch_size(void)
  69{
  70        int size;
  71
  72        size = parisc_agp_info.gart_size / MB(1);
  73        parisc_agp_sizes[0].size = size;
  74        agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
  75
  76        return size;
  77}
  78
  79static int
  80parisc_agp_configure(void)
  81{
  82        struct _parisc_agp_info *info = &parisc_agp_info;
  83
  84        agp_bridge->gart_bus_addr = info->gart_base;
  85        agp_bridge->capndx = info->lba_cap_offset;
  86        agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
  87
  88        return 0;
  89}
  90
  91static void
  92parisc_agp_tlbflush(struct agp_memory *mem)
  93{
  94        struct _parisc_agp_info *info = &parisc_agp_info;
  95
  96        writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
  97        readq(info->ioc_regs+IOC_PCOM); /* flush */
  98}
  99
 100static int
 101parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
 102{
 103        struct _parisc_agp_info *info = &parisc_agp_info;
 104        int i;
 105
 106        for (i = 0; i < info->gatt_entries; i++) {
 107                info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
 108        }
 109
 110        return 0;
 111}
 112
 113static int
 114parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
 115{
 116        struct _parisc_agp_info *info = &parisc_agp_info;
 117
 118        info->gatt[0] = SBA_AGPGART_COOKIE;
 119
 120        return 0;
 121}
 122
 123static int
 124parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
 125{
 126        struct _parisc_agp_info *info = &parisc_agp_info;
 127        int i, k;
 128        off_t j, io_pg_start;
 129        int io_pg_count;
 130
 131        if (type != 0 || mem->type != 0) {
 132                return -EINVAL;
 133        }
 134
 135        io_pg_start = info->io_pages_per_kpage * pg_start;
 136        io_pg_count = info->io_pages_per_kpage * mem->page_count;
 137        if ((io_pg_start + io_pg_count) > info->gatt_entries) {
 138                return -EINVAL;
 139        }
 140
 141        j = io_pg_start;
 142        while (j < (io_pg_start + io_pg_count)) {
 143                if (info->gatt[j])
 144                        return -EBUSY;
 145                j++;
 146        }
 147
 148        if (!mem->is_flushed) {
 149                global_cache_flush();
 150                mem->is_flushed = true;
 151        }
 152
 153        for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
 154                unsigned long paddr;
 155
 156                paddr = page_to_phys(mem->pages[i]);
 157                for (k = 0;
 158                     k < info->io_pages_per_kpage;
 159                     k++, j++, paddr += info->io_page_size) {
 160                        info->gatt[j] =
 161                                parisc_agp_mask_memory(agp_bridge,
 162                                        paddr, type);
 163                }
 164        }
 165
 166        agp_bridge->driver->tlb_flush(mem);
 167
 168        return 0;
 169}
 170
 171static int
 172parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 173{
 174        struct _parisc_agp_info *info = &parisc_agp_info;
 175        int i, io_pg_start, io_pg_count;
 176
 177        if (type != 0 || mem->type != 0) {
 178                return -EINVAL;
 179        }
 180
 181        io_pg_start = info->io_pages_per_kpage * pg_start;
 182        io_pg_count = info->io_pages_per_kpage * mem->page_count;
 183        for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
 184                info->gatt[i] = agp_bridge->scratch_page;
 185        }
 186
 187        agp_bridge->driver->tlb_flush(mem);
 188        return 0;
 189}
 190
 191static unsigned long
 192parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
 193                       int type)
 194{
 195        return SBA_PDIR_VALID_BIT | addr;
 196}
 197
 198static void
 199parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 200{
 201        struct _parisc_agp_info *info = &parisc_agp_info;
 202        u32 command;
 203
 204        command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
 205
 206        command = agp_collect_device_status(bridge, mode, command);
 207        command |= 0x00000100;
 208
 209        writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
 210
 211        agp_device_command(command, (mode & AGP8X_MODE) != 0);
 212}
 213
 214static const struct agp_bridge_driver parisc_agp_driver = {
 215        .owner                  = THIS_MODULE,
 216        .size_type              = FIXED_APER_SIZE,
 217        .configure              = parisc_agp_configure,
 218        .fetch_size             = parisc_agp_fetch_size,
 219        .tlb_flush              = parisc_agp_tlbflush,
 220        .mask_memory            = parisc_agp_mask_memory,
 221        .masks                  = parisc_agp_masks,
 222        .agp_enable             = parisc_agp_enable,
 223        .cache_flush            = global_cache_flush,
 224        .create_gatt_table      = parisc_agp_create_gatt_table,
 225        .free_gatt_table        = parisc_agp_free_gatt_table,
 226        .insert_memory          = parisc_agp_insert_memory,
 227        .remove_memory          = parisc_agp_remove_memory,
 228        .alloc_by_type          = agp_generic_alloc_by_type,
 229        .free_by_type           = agp_generic_free_by_type,
 230        .agp_alloc_page         = agp_generic_alloc_page,
 231        .agp_alloc_pages        = agp_generic_alloc_pages,
 232        .agp_destroy_page       = agp_generic_destroy_page,
 233        .agp_destroy_pages      = agp_generic_destroy_pages,
 234        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 235        .cant_use_aperture      = true,
 236};
 237
 238static int __init
 239agp_ioc_init(void __iomem *ioc_regs)
 240{
 241        struct _parisc_agp_info *info = &parisc_agp_info;
 242        u64 iova_base, *io_pdir, io_tlb_ps;
 243        int io_tlb_shift;
 244
 245        printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
 246
 247        info->ioc_regs = ioc_regs;
 248
 249        io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
 250        switch (io_tlb_ps) {
 251        case 0: io_tlb_shift = 12; break;
 252        case 1: io_tlb_shift = 13; break;
 253        case 2: io_tlb_shift = 14; break;
 254        case 3: io_tlb_shift = 16; break;
 255        default:
 256                printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
 257                       "configuration 0x%llx\n", io_tlb_ps);
 258                info->gatt = NULL;
 259                info->gatt_entries = 0;
 260                return -ENODEV;
 261        }
 262        info->io_page_size = 1 << io_tlb_shift;
 263        info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
 264
 265        iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
 266        info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
 267
 268        info->gart_size = PLUTO_GART_SIZE;
 269        info->gatt_entries = info->gart_size / info->io_page_size;
 270
 271        io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
 272        info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
 273
 274        if (info->gatt[0] != SBA_AGPGART_COOKIE) {
 275                info->gatt = NULL;
 276                info->gatt_entries = 0;
 277                printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
 278                       "GART disabled\n");
 279                return -ENODEV;
 280        }
 281
 282        return 0;
 283}
 284
 285static int
 286lba_find_capability(int cap)
 287{
 288        struct _parisc_agp_info *info = &parisc_agp_info;
 289        u16 status;
 290        u8 pos, id;
 291        int ttl = 48;
 292
 293        status = readw(info->lba_regs + PCI_STATUS);
 294        if (!(status & PCI_STATUS_CAP_LIST))
 295                return 0;
 296        pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
 297        while (ttl-- && pos >= 0x40) {
 298                pos &= ~3;
 299                id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
 300                if (id == 0xff)
 301                        break;
 302                if (id == cap)
 303                        return pos;
 304                pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
 305        }
 306        return 0;
 307}
 308
 309static int __init
 310agp_lba_init(void __iomem *lba_hpa)
 311{
 312        struct _parisc_agp_info *info = &parisc_agp_info;
 313        int cap;
 314
 315        info->lba_regs = lba_hpa;
 316        info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
 317
 318        cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
 319        if (cap != PCI_CAP_ID_AGP) {
 320                printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
 321                       cap, info->lba_cap_offset);
 322                return -ENODEV;
 323        }
 324
 325        return 0;
 326}
 327
 328static int __init
 329parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
 330{
 331        struct pci_dev *fake_bridge_dev = NULL;
 332        struct agp_bridge_data *bridge;
 333        int error = 0;
 334
 335        fake_bridge_dev = alloc_pci_dev();
 336        if (!fake_bridge_dev) {
 337                error = -ENOMEM;
 338                goto fail;
 339        }
 340
 341        error = agp_ioc_init(ioc_hpa);
 342        if (error)
 343                goto fail;
 344
 345        error = agp_lba_init(lba_hpa);
 346        if (error)
 347                goto fail;
 348
 349        bridge = agp_alloc_bridge();
 350        if (!bridge) {
 351                error = -ENOMEM;
 352                goto fail;
 353        }
 354        bridge->driver = &parisc_agp_driver;
 355
 356        fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
 357        fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
 358        bridge->dev = fake_bridge_dev;
 359
 360        error = agp_add_bridge(bridge);
 361
 362fail:
 363        return error;
 364}
 365
 366static int
 367find_quicksilver(struct device *dev, void *data)
 368{
 369        struct parisc_device **lba = data;
 370        struct parisc_device *padev = to_parisc_device(dev);
 371
 372        if (IS_QUICKSILVER(padev))
 373                *lba = padev;
 374
 375        return 0;
 376}
 377
 378static int
 379parisc_agp_init(void)
 380{
 381        extern struct sba_device *sba_list;
 382
 383        int err = -1;
 384        struct parisc_device *sba = NULL, *lba = NULL;
 385        struct lba_device *lbadev = NULL;
 386
 387        if (!sba_list)
 388                goto out;
 389
 390        /* Find our parent Pluto */
 391        sba = sba_list->dev;
 392        if (!IS_PLUTO(sba)) {
 393                printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
 394                goto out;
 395        }
 396
 397        /* Now search our Pluto for our precious AGP device... */
 398        device_for_each_child(&sba->dev, &lba, find_quicksilver);
 399
 400        if (!lba) {
 401                printk(KERN_INFO DRVPFX "No AGP devices found.\n");
 402                goto out;
 403        }
 404
 405        lbadev = parisc_get_drvdata(lba);
 406
 407        /* w00t, let's go find our cookies... */
 408        parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
 409
 410        return 0;
 411
 412out:
 413        return err;
 414}
 415
 416module_init(parisc_agp_init);
 417
 418MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
 419MODULE_LICENSE("GPL");
 420