Path: blob/master/arch/powerpc/platforms/pasemi/iommu.c
10819 views
/*1* Copyright (C) 2005-2008, PA Semi, Inc2*3* Maintained by: Olof Johansson <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License version 2 as7* published by the Free Software Foundation.8*9* This program is distributed in the hope that it will be useful,10* but WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12* GNU General Public License for more details.13*14* You should have received a copy of the GNU General Public License15* along with this program; if not, write to the Free Software16* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA17*/1819#undef DEBUG2021#include <linux/types.h>22#include <linux/spinlock.h>23#include <linux/pci.h>24#include <asm/iommu.h>25#include <asm/machdep.h>26#include <asm/abs_addr.h>27#include <asm/firmware.h>2829#define IOBMAP_PAGE_SHIFT 1230#define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT)31#define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1)3233#define IOB_BASE 0xe000000034#define IOB_SIZE 0x300035/* Configuration registers */36#define IOBCAP_REG 0x4037#define IOBCOM_REG 0x10038/* Enable IOB address translation */39#define IOBCOM_ATEN 0x000001004041/* Address decode configuration register */42#define IOB_AD_REG 0x14c43/* IOBCOM_AD_REG fields */44#define IOB_AD_VGPRT 0x00000e0045#define IOB_AD_VGAEN 0x0000010046/* Direct mapping settings */47#define IOB_AD_MPSEL_MASK 0x0000003048#define IOB_AD_MPSEL_B38 0x0000000049#define IOB_AD_MPSEL_B40 0x0000001050#define IOB_AD_MPSEL_B42 0x0000002051/* Translation window size / enable */52#define IOB_AD_TRNG_MASK 0x0000000353#define IOB_AD_TRNG_256M 0x0000000054#define IOB_AD_TRNG_2G 0x0000000155#define IOB_AD_TRNG_128G 0x000000035657#define IOB_TABLEBASE_REG 0x1545859/* Base of the 64 4-byte L1 registers */60#define IOB_XLT_L1_REGBASE 0x2b006162/* Register to invalidate TLB entries */63#define IOB_AT_INVAL_TLB_REG 0x2d006465/* The top two bits of the level 1 entry contains valid and type flags */66#define IOBMAP_L1E_V 0x4000000067#define IOBMAP_L1E_V_B 0x800000006869/* For big page entries, the bottom two bits contains flags */70#define IOBMAP_L1E_BIG_CACHED 0x0000000271#define IOBMAP_L1E_BIG_PRIORITY 0x000000017273/* For regular level 2 entries, top 2 bits contain valid and cache flags */74#define IOBMAP_L2E_V 0x8000000075#define IOBMAP_L2E_V_CACHED 0xc00000007677static void __iomem *iob;78static u32 iob_l1_emptyval;79static u32 iob_l2_emptyval;80static u32 *iob_l2_base;8182static struct iommu_table iommu_table_iobmap;83static int iommu_table_iobmap_inited;8485static int iobmap_build(struct iommu_table *tbl, long index,86long npages, unsigned long uaddr,87enum dma_data_direction direction,88struct dma_attrs *attrs)89{90u32 *ip;91u32 rpn;92unsigned long bus_addr;9394pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr);9596bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT;9798ip = ((u32 *)tbl->it_base) + index;99100while (npages--) {101rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT;102103*(ip++) = IOBMAP_L2E_V | rpn;104/* invalidate tlb, can be optimized more */105out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);106107uaddr += IOBMAP_PAGE_SIZE;108bus_addr += IOBMAP_PAGE_SIZE;109}110return 0;111}112113114static void iobmap_free(struct iommu_table *tbl, long index,115long npages)116{117u32 *ip;118unsigned long bus_addr;119120pr_debug("iobmap: free at: %lx, %lx\n", index, npages);121122bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT;123124ip = ((u32 *)tbl->it_base) + index;125126while (npages--) {127*(ip++) = iob_l2_emptyval;128/* invalidate tlb, can be optimized more */129out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);130bus_addr += IOBMAP_PAGE_SIZE;131}132}133134135static void iommu_table_iobmap_setup(void)136{137pr_debug(" -> %s\n", __func__);138iommu_table_iobmap.it_busno = 0;139iommu_table_iobmap.it_offset = 0;140/* it_size is in number of entries */141iommu_table_iobmap.it_size = 0x80000000 >> IOBMAP_PAGE_SHIFT;142143/* Initialize the common IOMMU code */144iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;145iommu_table_iobmap.it_index = 0;146/* XXXOJN tune this to avoid IOB cache invals.147* Should probably be 8 (64 bytes)148*/149iommu_table_iobmap.it_blocksize = 4;150iommu_init_table(&iommu_table_iobmap, 0);151pr_debug(" <- %s\n", __func__);152}153154155156static void pci_dma_bus_setup_pasemi(struct pci_bus *bus)157{158pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self);159160if (!iommu_table_iobmap_inited) {161iommu_table_iobmap_inited = 1;162iommu_table_iobmap_setup();163}164}165166167static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)168{169pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));170171#if !defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)172/* For non-LPAR environment, don't translate anything for the DMA173* engine. The exception to this is if the user has enabled174* CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time.175*/176if (dev->vendor == 0x1959 && dev->device == 0xa007 &&177!firmware_has_feature(FW_FEATURE_LPAR)) {178dev->dev.archdata.dma_ops = &dma_direct_ops;179return;180}181#endif182183set_iommu_table_base(&dev->dev, &iommu_table_iobmap);184}185186int __init iob_init(struct device_node *dn)187{188unsigned long tmp;189u32 regword;190int i;191192pr_debug(" -> %s\n", __func__);193194/* Allocate a spare page to map all invalid IOTLB pages. */195tmp = memblock_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE);196if (!tmp)197panic("IOBMAP: Cannot allocate spare page!");198/* Empty l1 is marked invalid */199iob_l1_emptyval = 0;200/* Empty l2 is mapped to dummy page */201iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT);202203iob = ioremap(IOB_BASE, IOB_SIZE);204if (!iob)205panic("IOBMAP: Cannot map registers!");206207/* setup direct mapping of the L1 entries */208for (i = 0; i < 64; i++) {209/* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */210regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12);211out_le32(iob+IOB_XLT_L1_REGBASE+i*4, regword);212}213214/* set 2GB translation window, based at 0 */215regword = in_le32(iob+IOB_AD_REG);216regword &= ~IOB_AD_TRNG_MASK;217regword |= IOB_AD_TRNG_2G;218out_le32(iob+IOB_AD_REG, regword);219220/* Enable translation */221regword = in_le32(iob+IOBCOM_REG);222regword |= IOBCOM_ATEN;223out_le32(iob+IOBCOM_REG, regword);224225pr_debug(" <- %s\n", __func__);226227return 0;228}229230231/* These are called very early. */232void __init iommu_init_early_pasemi(void)233{234int iommu_off;235236#ifndef CONFIG_PPC_PASEMI_IOMMU237iommu_off = 1;238#else239iommu_off = of_chosen &&240of_get_property(of_chosen, "linux,iommu-off", NULL);241#endif242if (iommu_off)243return;244245iob_init(NULL);246247ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi;248ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;249ppc_md.tce_build = iobmap_build;250ppc_md.tce_free = iobmap_free;251set_pci_dma_ops(&dma_iommu_ops);252}253254void __init alloc_iobmap_l2(void)255{256#ifndef CONFIG_PPC_PASEMI_IOMMU257return;258#endif259/* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */260iob_l2_base = (u32 *)abs_to_virt(memblock_alloc_base(1UL<<21, 1UL<<21, 0x80000000));261262printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base);263}264265266