Path: blob/master/arch/powerpc/platforms/cell/spider-pci.c
10818 views
/*1* IO workarounds for PCI on Celleb/Cell platform2*3* (C) Copyright 2006-2007 TOSHIBA CORPORATION4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License along16* with this program; if not, write to the Free Software Foundation, Inc.,17* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.18*/1920#undef DEBUG2122#include <linux/kernel.h>23#include <linux/of_platform.h>24#include <linux/slab.h>25#include <linux/io.h>2627#include <asm/ppc-pci.h>28#include <asm/pci-bridge.h>29#include <asm/io-workarounds.h>3031#define SPIDER_PCI_DISABLE_PREFETCH3233struct spiderpci_iowa_private {34void __iomem *regs;35};3637static void spiderpci_io_flush(struct iowa_bus *bus)38{39struct spiderpci_iowa_private *priv;40u32 val;4142priv = bus->private;43val = in_be32(priv->regs + SPIDER_PCI_DUMMY_READ);44iosync();45}4647#define SPIDER_PCI_MMIO_READ(name, ret) \48static ret spiderpci_##name(const PCI_IO_ADDR addr) \49{ \50ret val = __do_##name(addr); \51spiderpci_io_flush(iowa_mem_find_bus(addr)); \52return val; \53}5455#define SPIDER_PCI_MMIO_READ_STR(name) \56static void spiderpci_##name(const PCI_IO_ADDR addr, void *buf, \57unsigned long count) \58{ \59__do_##name(addr, buf, count); \60spiderpci_io_flush(iowa_mem_find_bus(addr)); \61}6263SPIDER_PCI_MMIO_READ(readb, u8)64SPIDER_PCI_MMIO_READ(readw, u16)65SPIDER_PCI_MMIO_READ(readl, u32)66SPIDER_PCI_MMIO_READ(readq, u64)67SPIDER_PCI_MMIO_READ(readw_be, u16)68SPIDER_PCI_MMIO_READ(readl_be, u32)69SPIDER_PCI_MMIO_READ(readq_be, u64)70SPIDER_PCI_MMIO_READ_STR(readsb)71SPIDER_PCI_MMIO_READ_STR(readsw)72SPIDER_PCI_MMIO_READ_STR(readsl)7374static void spiderpci_memcpy_fromio(void *dest, const PCI_IO_ADDR src,75unsigned long n)76{77__do_memcpy_fromio(dest, src, n);78spiderpci_io_flush(iowa_mem_find_bus(src));79}8081static int __init spiderpci_pci_setup_chip(struct pci_controller *phb,82void __iomem *regs)83{84void *dummy_page_va;85dma_addr_t dummy_page_da;8687#ifdef SPIDER_PCI_DISABLE_PREFETCH88u32 val = in_be32(regs + SPIDER_PCI_VCI_CNTL_STAT);89pr_debug("SPIDER_IOWA:PVCI_Control_Status was 0x%08x\n", val);90out_be32(regs + SPIDER_PCI_VCI_CNTL_STAT, val | 0x8);91#endif /* SPIDER_PCI_DISABLE_PREFETCH */9293/* setup dummy read */94/*95* On CellBlade, we can't know that which XDR memory is used by96* kmalloc() to allocate dummy_page_va.97* In order to imporve the performance, the XDR which is used to98* allocate dummy_page_va is the nearest the spider-pci.99* We have to select the CBE which is the nearest the spider-pci100* to allocate memory from the best XDR, but I don't know that101* how to do.102*103* Celleb does not have this problem, because it has only one XDR.104*/105dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL);106if (!dummy_page_va) {107pr_err("SPIDERPCI-IOWA:Alloc dummy_page_va failed.\n");108return -1;109}110111dummy_page_da = dma_map_single(phb->parent, dummy_page_va,112PAGE_SIZE, DMA_FROM_DEVICE);113if (dma_mapping_error(phb->parent, dummy_page_da)) {114pr_err("SPIDER-IOWA:Map dummy page filed.\n");115kfree(dummy_page_va);116return -1;117}118119out_be32(regs + SPIDER_PCI_DUMMY_READ_BASE, dummy_page_da);120121return 0;122}123124int __init spiderpci_iowa_init(struct iowa_bus *bus, void *data)125{126void __iomem *regs = NULL;127struct spiderpci_iowa_private *priv;128struct device_node *np = bus->phb->dn;129struct resource r;130unsigned long offset = (unsigned long)data;131132pr_debug("SPIDERPCI-IOWA:Bus initialize for spider(%s)\n",133np->full_name);134135priv = kzalloc(sizeof(struct spiderpci_iowa_private), GFP_KERNEL);136if (!priv) {137pr_err("SPIDERPCI-IOWA:"138"Can't allocate struct spiderpci_iowa_private");139return -1;140}141142if (of_address_to_resource(np, 0, &r)) {143pr_err("SPIDERPCI-IOWA:Can't get resource.\n");144goto error;145}146147regs = ioremap(r.start + offset, SPIDER_PCI_REG_SIZE);148if (!regs) {149pr_err("SPIDERPCI-IOWA:ioremap failed.\n");150goto error;151}152priv->regs = regs;153bus->private = priv;154155if (spiderpci_pci_setup_chip(bus->phb, regs))156goto error;157158return 0;159160error:161kfree(priv);162bus->private = NULL;163164if (regs)165iounmap(regs);166167return -1;168}169170struct ppc_pci_io spiderpci_ops = {171.readb = spiderpci_readb,172.readw = spiderpci_readw,173.readl = spiderpci_readl,174.readq = spiderpci_readq,175.readw_be = spiderpci_readw_be,176.readl_be = spiderpci_readl_be,177.readq_be = spiderpci_readq_be,178.readsb = spiderpci_readsb,179.readsw = spiderpci_readsw,180.readsl = spiderpci_readsl,181.memcpy_fromio = spiderpci_memcpy_fromio,182};183184185186