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