linux/arch/powerpc/platforms/cell/io-workarounds.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>
   3 *                     IBM, Corp.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9#undef DEBUG
  10
  11#include <linux/kernel.h>
  12#include <linux/mm.h>
  13#include <linux/pci.h>
  14#include <asm/io.h>
  15#include <asm/machdep.h>
  16#include <asm/pci-bridge.h>
  17#include <asm/ppc-pci.h>
  18
  19
  20#define SPIDER_PCI_REG_BASE             0xd000
  21#define SPIDER_PCI_VCI_CNTL_STAT        0x0110
  22#define SPIDER_PCI_DUMMY_READ           0x0810
  23#define SPIDER_PCI_DUMMY_READ_BASE      0x0814
  24
  25/* Undefine that to re-enable bogus prefetch
  26 *
  27 * Without that workaround, the chip will do bogus prefetch past
  28 * page boundary from system memory. This setting will disable that,
  29 * though the documentation is unclear as to the consequences of doing
  30 * so, either purely performances, or possible misbehaviour... It's not
  31 * clear wether the chip can handle unaligned accesses at all without
  32 * prefetching enabled.
  33 *
  34 * For now, things appear to be behaving properly with that prefetching
  35 * disabled and IDE, possibly because IDE isn't doing any unaligned
  36 * access.
  37 */
  38#define SPIDER_DISABLE_PREFETCH
  39
  40#define MAX_SPIDERS     3
  41
  42static struct spider_pci_bus {
  43        void __iomem    *regs;
  44        unsigned long   mmio_start;
  45        unsigned long   mmio_end;
  46        unsigned long   pio_vstart;
  47        unsigned long   pio_vend;
  48} spider_pci_busses[MAX_SPIDERS];
  49static int spider_pci_count;
  50
  51static struct spider_pci_bus *spider_pci_find(unsigned long vaddr,
  52                                              unsigned long paddr)
  53{
  54        int i;
  55
  56        for (i = 0; i < spider_pci_count; i++) {
  57                struct spider_pci_bus *bus = &spider_pci_busses[i];
  58                if (paddr && paddr >= bus->mmio_start && paddr < bus->mmio_end)
  59                        return bus;
  60                if (vaddr && vaddr >= bus->pio_vstart && vaddr < bus->pio_vend)
  61                        return bus;
  62        }
  63        return NULL;
  64}
  65
  66static void spider_io_flush(const volatile void __iomem *addr)
  67{
  68        struct spider_pci_bus *bus;
  69        int token;
  70
  71        /* Get platform token (set by ioremap) from address */
  72        token = PCI_GET_ADDR_TOKEN(addr);
  73
  74        /* Fast path if we have a non-0 token, it indicates which bus we
  75         * are on.
  76         *
  77         * If the token is 0, that means either that the ioremap was done
  78         * before we initialized this layer, or it's a PIO operation. We
  79         * fallback to a low path in this case. Hopefully, internal devices
  80         * which are ioremap'ed early should use in_XX/out_XX functions
  81         * instead of the PCI ones and thus not suffer from the slowdown.
  82         *
  83         * Also note that currently, the workaround will not work for areas
  84         * that are not mapped with PTEs (bolted in the hash table). This
  85         * is the case for ioremaps done very early at boot (before
  86         * mem_init_done) and includes the mapping of the ISA IO space.
  87         *
  88         * Fortunately, none of the affected devices is expected to do DMA
  89         * and thus there should be no problem in practice.
  90         *
  91         * In order to improve performances, we only do the PTE search for
  92         * addresses falling in the PHB IO space area. That means it will
  93         * not work for hotplug'ed PHBs but those don't exist with Spider.
  94         */
  95        if (token && token <= spider_pci_count)
  96                bus = &spider_pci_busses[token - 1];
  97        else {
  98                unsigned long vaddr, paddr;
  99                pte_t *ptep;
 100
 101                /* Fixup physical address */
 102                vaddr = (unsigned long)PCI_FIX_ADDR(addr);
 103
 104                /* Check if it's in allowed range for  PIO */
 105                if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
 106                        return;
 107
 108                /* Try to find a PTE. If not, clear the paddr, we'll do
 109                 * a vaddr only lookup (PIO only)
 110                 */
 111                ptep = find_linux_pte(init_mm.pgd, vaddr);
 112                if (ptep == NULL)
 113                        paddr = 0;
 114                else
 115                        paddr = pte_pfn(*ptep) << PAGE_SHIFT;
 116
 117                bus = spider_pci_find(vaddr, paddr);
 118                if (bus == NULL)
 119                        return;
 120        }
 121
 122        /* Now do the workaround
 123         */
 124        (void)in_be32(bus->regs + SPIDER_PCI_DUMMY_READ);
 125}
 126
 127static u8 spider_readb(const volatile void __iomem *addr)
 128{
 129        u8 val = __do_readb(addr);
 130        spider_io_flush(addr);
 131        return val;
 132}
 133
 134static u16 spider_readw(const volatile void __iomem *addr)
 135{
 136        u16 val = __do_readw(addr);
 137        spider_io_flush(addr);
 138        return val;
 139}
 140
 141static u32 spider_readl(const volatile void __iomem *addr)
 142{
 143        u32 val = __do_readl(addr);
 144        spider_io_flush(addr);
 145        return val;
 146}
 147
 148static u64 spider_readq(const volatile void __iomem *addr)
 149{
 150        u64 val = __do_readq(addr);
 151        spider_io_flush(addr);
 152        return val;
 153}
 154
 155static u16 spider_readw_be(const volatile void __iomem *addr)
 156{
 157        u16 val = __do_readw_be(addr);
 158        spider_io_flush(addr);
 159        return val;
 160}
 161
 162static u32 spider_readl_be(const volatile void __iomem *addr)
 163{
 164        u32 val = __do_readl_be(addr);
 165        spider_io_flush(addr);
 166        return val;
 167}
 168
 169static u64 spider_readq_be(const volatile void __iomem *addr)
 170{
 171        u64 val = __do_readq_be(addr);
 172        spider_io_flush(addr);
 173        return val;
 174}
 175
 176static void spider_readsb(const volatile void __iomem *addr, void *buf,
 177                          unsigned long count)
 178{
 179        __do_readsb(addr, buf, count);
 180        spider_io_flush(addr);
 181}
 182
 183static void spider_readsw(const volatile void __iomem *addr, void *buf,
 184                          unsigned long count)
 185{
 186        __do_readsw(addr, buf, count);
 187        spider_io_flush(addr);
 188}
 189
 190static void spider_readsl(const volatile void __iomem *addr, void *buf,
 191                          unsigned long count)
 192{
 193        __do_readsl(addr, buf, count);
 194        spider_io_flush(addr);
 195}
 196
 197static void spider_memcpy_fromio(void *dest, const volatile void __iomem *src,
 198                                 unsigned long n)
 199{
 200        __do_memcpy_fromio(dest, src, n);
 201        spider_io_flush(src);
 202}
 203
 204
 205static void __iomem * spider_ioremap(unsigned long addr, unsigned long size,
 206                                     unsigned long flags)
 207{
 208        struct spider_pci_bus *bus;
 209        void __iomem *res = __ioremap(addr, size, flags);
 210        int busno;
 211
 212        pr_debug("spider_ioremap(0x%lx, 0x%lx, 0x%lx) -> 0x%p\n",
 213                 addr, size, flags, res);
 214
 215        bus = spider_pci_find(0, addr);
 216        if (bus != NULL) {
 217                busno = bus - spider_pci_busses;
 218                pr_debug(" found bus %d, setting token\n", busno);
 219                PCI_SET_ADDR_TOKEN(res, busno + 1);
 220        }
 221        pr_debug(" result=0x%p\n", res);
 222
 223        return res;
 224}
 225
 226static void __init spider_pci_setup_chip(struct spider_pci_bus *bus)
 227{
 228#ifdef SPIDER_DISABLE_PREFETCH
 229        u32 val = in_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT);
 230        pr_debug(" PVCI_Control_Status was 0x%08x\n", val);
 231        out_be32(bus->regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);
 232#endif
 233
 234        /* Configure the dummy address for the workaround */
 235        out_be32(bus->regs + SPIDER_PCI_DUMMY_READ_BASE, 0x80000000);
 236}
 237
 238static void __init spider_pci_add_one(struct pci_controller *phb)
 239{
 240        struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count];
 241        struct device_node *np = phb->arch_data;
 242        struct resource rsrc;
 243        void __iomem *regs;
 244
 245        if (spider_pci_count >= MAX_SPIDERS) {
 246                printk(KERN_ERR "Too many spider bridges, workarounds"
 247                       " disabled for %s\n", np->full_name);
 248                return;
 249        }
 250
 251        /* Get the registers for the beast */
 252        if (of_address_to_resource(np, 0, &rsrc)) {
 253                printk(KERN_ERR "Failed to get registers for spider %s"
 254                       " workarounds disabled\n", np->full_name);
 255                return;
 256        }
 257
 258        /* Mask out some useless bits in there to get to the base of the
 259         * spider chip
 260         */
 261        rsrc.start &= ~0xfffffffful;
 262
 263        /* Map them */
 264        regs = ioremap(rsrc.start + SPIDER_PCI_REG_BASE, 0x1000);
 265        if (regs == NULL) {
 266                printk(KERN_ERR "Failed to map registers for spider %s"
 267                       " workarounds disabled\n", np->full_name);
 268                return;
 269        }
 270
 271        spider_pci_count++;
 272
 273        /* We assume spiders only have one MMIO resource */
 274        bus->mmio_start = phb->mem_resources[0].start;
 275        bus->mmio_end = phb->mem_resources[0].end + 1;
 276
 277        bus->pio_vstart = (unsigned long)phb->io_base_virt;
 278        bus->pio_vend = bus->pio_vstart + phb->pci_io_size;
 279
 280        bus->regs = regs;
 281
 282        printk(KERN_INFO "PCI: Spider MMIO workaround for %s\n",np->full_name);
 283
 284        pr_debug(" mmio (P) = 0x%016lx..0x%016lx\n",
 285                 bus->mmio_start, bus->mmio_end);
 286        pr_debug("  pio (V) = 0x%016lx..0x%016lx\n",
 287                 bus->pio_vstart, bus->pio_vend);
 288        pr_debug(" regs (P) = 0x%016lx (V) = 0x%p\n",
 289                 rsrc.start + SPIDER_PCI_REG_BASE, bus->regs);
 290
 291        spider_pci_setup_chip(bus);
 292}
 293
 294static struct ppc_pci_io __initdata spider_pci_io = {
 295        .readb = spider_readb,
 296        .readw = spider_readw,
 297        .readl = spider_readl,
 298        .readq = spider_readq,
 299        .readw_be = spider_readw_be,
 300        .readl_be = spider_readl_be,
 301        .readq_be = spider_readq_be,
 302        .readsb = spider_readsb,
 303        .readsw = spider_readsw,
 304        .readsl = spider_readsl,
 305        .memcpy_fromio = spider_memcpy_fromio,
 306};
 307
 308static int __init spider_pci_workaround_init(void)
 309{
 310        struct pci_controller *phb;
 311
 312        if (!machine_is(cell))
 313                return 0;
 314
 315        /* Find spider bridges. We assume they have been all probed
 316         * in setup_arch(). If that was to change, we would need to
 317         * update this code to cope with dynamically added busses
 318         */
 319        list_for_each_entry(phb, &hose_list, list_node) {
 320                struct device_node *np = phb->arch_data;
 321                const char *model = of_get_property(np, "model", NULL);
 322
 323                /* If no model property or name isn't exactly "pci", skip */
 324                if (model == NULL || strcmp(np->name, "pci"))
 325                        continue;
 326                /* If model is not "Spider", skip */
 327                if (strcmp(model, "Spider"))
 328                        continue;
 329                spider_pci_add_one(phb);
 330        }
 331
 332        /* No Spider PCI found, exit */
 333        if (spider_pci_count == 0)
 334                return 0;
 335
 336        /* Setup IO callbacks. We only setup MMIO reads. PIO reads will
 337         * fallback to MMIO reads (though without a token, thus slower)
 338         */
 339        ppc_pci_io = spider_pci_io;
 340
 341        /* Setup ioremap callback */
 342        ppc_md.ioremap = spider_ioremap;
 343
 344        return 0;
 345}
 346arch_initcall(spider_pci_workaround_init);
 347