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 != 0 || mem->type != 0) {
 133                return -EINVAL;
 134        }
 135
 136        io_pg_start = info->io_pages_per_kpage * pg_start;
 137        io_pg_count = info->io_pages_per_kpage * mem->page_count;
 138        if ((io_pg_start + io_pg_count) > info->gatt_entries) {
 139                return -EINVAL;
 140        }
 141
 142        j = io_pg_start;
 143        while (j < (io_pg_start + io_pg_count)) {
 144                if (info->gatt[j])
 145                        return -EBUSY;
 146                j++;
 147        }
 148
 149        if (!mem->is_flushed) {
 150                global_cache_flush();
 151                mem->is_flushed = true;
 152        }
 153
 154        for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
 155                unsigned long paddr;
 156
 157                paddr = page_to_phys(mem->pages[i]);
 158                for (k = 0;
 159                     k < info->io_pages_per_kpage;
 160                     k++, j++, paddr += info->io_page_size) {
 161                        info->gatt[j] =
 162                                parisc_agp_mask_memory(agp_bridge,
 163                                        paddr, type);
 164                }
 165        }
 166
 167        agp_bridge->driver->tlb_flush(mem);
 168
 169        return 0;
 170}
 171
 172static int
 173parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
 174{
 175        struct _parisc_agp_info *info = &parisc_agp_info;
 176        int i, io_pg_start, io_pg_count;
 177
 178        if (type != 0 || mem->type != 0) {
 179                return -EINVAL;
 180        }
 181
 182        io_pg_start = info->io_pages_per_kpage * pg_start;
 183        io_pg_count = info->io_pages_per_kpage * mem->page_count;
 184        for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
 185                info->gatt[i] = agp_bridge->scratch_page;
 186        }
 187
 188        agp_bridge->driver->tlb_flush(mem);
 189        return 0;
 190}
 191
 192static unsigned long
 193parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
 194                       int type)
 195{
 196        return SBA_PDIR_VALID_BIT | addr;
 197}
 198
 199static void
 200parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 201{
 202        struct _parisc_agp_info *info = &parisc_agp_info;
 203        u32 command;
 204
 205        command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
 206
 207        command = agp_collect_device_status(bridge, mode, command);
 208        command |= 0x00000100;
 209
 210        writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
 211
 212        agp_device_command(command, (mode & AGP8X_MODE) != 0);
 213}
 214
 215static const struct agp_bridge_driver parisc_agp_driver = {
 216        .owner                  = THIS_MODULE,
 217        .size_type              = FIXED_APER_SIZE,
 218        .configure              = parisc_agp_configure,
 219        .fetch_size             = parisc_agp_fetch_size,
 220        .tlb_flush              = parisc_agp_tlbflush,
 221        .mask_memory            = parisc_agp_mask_memory,
 222        .masks                  = parisc_agp_masks,
 223        .agp_enable             = parisc_agp_enable,
 224        .cache_flush            = global_cache_flush,
 225        .create_gatt_table      = parisc_agp_create_gatt_table,
 226        .free_gatt_table        = parisc_agp_free_gatt_table,
 227        .insert_memory          = parisc_agp_insert_memory,
 228        .remove_memory          = parisc_agp_remove_memory,
 229        .alloc_by_type          = agp_generic_alloc_by_type,
 230        .free_by_type           = agp_generic_free_by_type,
 231        .agp_alloc_page         = agp_generic_alloc_page,
 232        .agp_alloc_pages        = agp_generic_alloc_pages,
 233        .agp_destroy_page       = agp_generic_destroy_page,
 234        .agp_destroy_pages      = agp_generic_destroy_pages,
 235        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 236        .cant_use_aperture      = true,
 237};
 238
 239static int __init
 240agp_ioc_init(void __iomem *ioc_regs)
 241{
 242        struct _parisc_agp_info *info = &parisc_agp_info;
 243        u64 iova_base, *io_pdir, io_tlb_ps;
 244        int io_tlb_shift;
 245
 246        printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
 247
 248        info->ioc_regs = ioc_regs;
 249
 250        io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
 251        switch (io_tlb_ps) {
 252        case 0: io_tlb_shift = 12; break;
 253        case 1: io_tlb_shift = 13; break;
 254        case 2: io_tlb_shift = 14; break;
 255        case 3: io_tlb_shift = 16; break;
 256        default:
 257                printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
 258                       "configuration 0x%llx\n", io_tlb_ps);
 259                info->gatt = NULL;
 260                info->gatt_entries = 0;
 261                return -ENODEV;
 262        }
 263        info->io_page_size = 1 << io_tlb_shift;
 264        info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
 265
 266        iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
 267        info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
 268
 269        info->gart_size = PLUTO_GART_SIZE;
 270        info->gatt_entries = info->gart_size / info->io_page_size;
 271
 272        io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
 273        info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
 274
 275        if (info->gatt[0] != SBA_AGPGART_COOKIE) {
 276                info->gatt = NULL;
 277                info->gatt_entries = 0;
 278                printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
 279                       "GART disabled\n");
 280                return -ENODEV;
 281        }
 282
 283        return 0;
 284}
 285
 286static int
 287lba_find_capability(int cap)
 288{
 289        struct _parisc_agp_info *info = &parisc_agp_info;
 290        u16 status;
 291        u8 pos, id;
 292        int ttl = 48;
 293
 294        status = readw(info->lba_regs + PCI_STATUS);
 295        if (!(status & PCI_STATUS_CAP_LIST))
 296                return 0;
 297        pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
 298        while (ttl-- && pos >= 0x40) {
 299                pos &= ~3;
 300                id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
 301                if (id == 0xff)
 302                        break;
 303                if (id == cap)
 304                        return pos;
 305                pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
 306        }
 307        return 0;
 308}
 309
 310static int __init
 311agp_lba_init(void __iomem *lba_hpa)
 312{
 313        struct _parisc_agp_info *info = &parisc_agp_info;
 314        int cap;
 315
 316        info->lba_regs = lba_hpa;
 317        info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
 318
 319        cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
 320        if (cap != PCI_CAP_ID_AGP) {
 321                printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
 322                       cap, info->lba_cap_offset);
 323                return -ENODEV;
 324        }
 325
 326        return 0;
 327}
 328
 329static int __init
 330parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
 331{
 332        struct pci_dev *fake_bridge_dev = NULL;
 333        struct agp_bridge_data *bridge;
 334        int error = 0;
 335
 336        fake_bridge_dev = alloc_pci_dev();
 337        if (!fake_bridge_dev) {
 338                error = -ENOMEM;
 339                goto fail;
 340        }
 341
 342        error = agp_ioc_init(ioc_hpa);
 343        if (error)
 344                goto fail;
 345
 346        error = agp_lba_init(lba_hpa);
 347        if (error)
 348                goto fail;
 349
 350        bridge = agp_alloc_bridge();
 351        if (!bridge) {
 352                error = -ENOMEM;
 353                goto fail;
 354        }
 355        bridge->driver = &parisc_agp_driver;
 356
 357        fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
 358        fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
 359        bridge->dev = fake_bridge_dev;
 360
 361        error = agp_add_bridge(bridge);
 362        if (error)
 363                goto fail;
 364        return 0;
 365
 366fail:
 367        kfree(fake_bridge_dev);
 368        return error;
 369}
 370
 371static int
 372find_quicksilver(struct device *dev, void *data)
 373{
 374        struct parisc_device **lba = data;
 375        struct parisc_device *padev = to_parisc_device(dev);
 376
 377        if (IS_QUICKSILVER(padev))
 378                *lba = padev;
 379
 380        return 0;
 381}
 382
 383static int
 384parisc_agp_init(void)
 385{
 386        extern struct sba_device *sba_list;
 387
 388        int err = -1;
 389        struct parisc_device *sba = NULL, *lba = NULL;
 390        struct lba_device *lbadev = NULL;
 391
 392        if (!sba_list)
 393                goto out;
 394
 395        /* Find our parent Pluto */
 396        sba = sba_list->dev;
 397        if (!IS_PLUTO(sba)) {
 398                printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
 399                goto out;
 400        }
 401
 402        /* Now search our Pluto for our precious AGP device... */
 403        device_for_each_child(&sba->dev, &lba, find_quicksilver);
 404
 405        if (!lba) {
 406                printk(KERN_INFO DRVPFX "No AGP devices found.\n");
 407                goto out;
 408        }
 409
 410        lbadev = parisc_get_drvdata(lba);
 411
 412        /* w00t, let's go find our cookies... */
 413        parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
 414
 415        return 0;
 416
 417out:
 418        return err;
 419}
 420
 421module_init(parisc_agp_init);
 422
 423MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
 424MODULE_LICENSE("GPL");
 425
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.