Path: blob/master/arch/powerpc/platforms/pasemi/iommu.c
26489 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2005-2008, PA Semi, Inc3*4* Maintained by: Olof Johansson <[email protected]>5*/67#undef DEBUG89#include <linux/memblock.h>10#include <linux/types.h>11#include <linux/spinlock.h>12#include <linux/pci.h>13#include <linux/of.h>14#include <asm/iommu.h>15#include <asm/machdep.h>16#include <asm/firmware.h>1718#include "pasemi.h"1920#define IOBMAP_PAGE_SHIFT 1221#define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT)22#define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1)2324#define IOB_BASE 0xe000000025#define IOB_SIZE 0x300026/* Configuration registers */27#define IOBCAP_REG 0x4028#define IOBCOM_REG 0x10029/* Enable IOB address translation */30#define IOBCOM_ATEN 0x000001003132/* Address decode configuration register */33#define IOB_AD_REG 0x14c34/* IOBCOM_AD_REG fields */35#define IOB_AD_VGPRT 0x00000e0036#define IOB_AD_VGAEN 0x0000010037/* Direct mapping settings */38#define IOB_AD_MPSEL_MASK 0x0000003039#define IOB_AD_MPSEL_B38 0x0000000040#define IOB_AD_MPSEL_B40 0x0000001041#define IOB_AD_MPSEL_B42 0x0000002042/* Translation window size / enable */43#define IOB_AD_TRNG_MASK 0x0000000344#define IOB_AD_TRNG_256M 0x0000000045#define IOB_AD_TRNG_2G 0x0000000146#define IOB_AD_TRNG_128G 0x000000034748#define IOB_TABLEBASE_REG 0x1544950/* Base of the 64 4-byte L1 registers */51#define IOB_XLT_L1_REGBASE 0x2b005253/* Register to invalidate TLB entries */54#define IOB_AT_INVAL_TLB_REG 0x2d005556/* The top two bits of the level 1 entry contains valid and type flags */57#define IOBMAP_L1E_V 0x4000000058#define IOBMAP_L1E_V_B 0x800000005960/* For big page entries, the bottom two bits contains flags */61#define IOBMAP_L1E_BIG_CACHED 0x0000000262#define IOBMAP_L1E_BIG_PRIORITY 0x000000016364/* For regular level 2 entries, top 2 bits contain valid and cache flags */65#define IOBMAP_L2E_V 0x8000000066#define IOBMAP_L2E_V_CACHED 0xc00000006768static void __iomem *iob;69static u32 iob_l1_emptyval;70static u32 iob_l2_emptyval;71static u32 *iob_l2_base;7273static struct iommu_table iommu_table_iobmap;74static int iommu_table_iobmap_inited;7576static int iobmap_build(struct iommu_table *tbl, long index,77long npages, unsigned long uaddr,78enum dma_data_direction direction,79unsigned long attrs)80{81u32 *ip;82u32 rpn;83unsigned long bus_addr;8485pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr);8687bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT;8889ip = ((u32 *)tbl->it_base) + index;9091while (npages--) {92rpn = __pa(uaddr) >> IOBMAP_PAGE_SHIFT;9394*(ip++) = IOBMAP_L2E_V | rpn;95/* invalidate tlb, can be optimized more */96out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);9798uaddr += IOBMAP_PAGE_SIZE;99bus_addr += IOBMAP_PAGE_SIZE;100}101return 0;102}103104105static void iobmap_free(struct iommu_table *tbl, long index,106long npages)107{108u32 *ip;109unsigned long bus_addr;110111pr_debug("iobmap: free at: %lx, %lx\n", index, npages);112113bus_addr = (tbl->it_offset + index) << IOBMAP_PAGE_SHIFT;114115ip = ((u32 *)tbl->it_base) + index;116117while (npages--) {118*(ip++) = iob_l2_emptyval;119/* invalidate tlb, can be optimized more */120out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);121bus_addr += IOBMAP_PAGE_SIZE;122}123}124125static struct iommu_table_ops iommu_table_iobmap_ops = {126.set = iobmap_build,127.clear = iobmap_free128};129130static void iommu_table_iobmap_setup(void)131{132pr_debug(" -> %s\n", __func__);133iommu_table_iobmap.it_busno = 0;134iommu_table_iobmap.it_offset = 0;135iommu_table_iobmap.it_page_shift = IOBMAP_PAGE_SHIFT;136137/* it_size is in number of entries */138iommu_table_iobmap.it_size =1390x80000000 >> iommu_table_iobmap.it_page_shift;140141/* Initialize the common IOMMU code */142iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;143iommu_table_iobmap.it_index = 0;144/* XXXOJN tune this to avoid IOB cache invals.145* Should probably be 8 (64 bytes)146*/147iommu_table_iobmap.it_blocksize = 4;148iommu_table_iobmap.it_ops = &iommu_table_iobmap_ops;149if (!iommu_init_table(&iommu_table_iobmap, 0, 0, 0))150panic("Failed to initialize iommu table");151152pr_debug(" <- %s\n", __func__);153}154155156157static void pci_dma_bus_setup_pasemi(struct pci_bus *bus)158{159pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self);160161if (!iommu_table_iobmap_inited) {162iommu_table_iobmap_inited = 1;163iommu_table_iobmap_setup();164}165}166167168static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)169{170pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));171172#if !defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)173/* For non-LPAR environment, don't translate anything for the DMA174* engine. The exception to this is if the user has enabled175* CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE at build time.176*/177if (dev->vendor == 0x1959 && dev->device == 0xa007 &&178!firmware_has_feature(FW_FEATURE_LPAR)) {179dev->dev.dma_ops = NULL;180/*181* Set the coherent DMA mask to prevent the iommu182* being used unnecessarily183*/184dev->dev.coherent_dma_mask = DMA_BIT_MASK(44);185return;186}187#endif188189set_iommu_table_base(&dev->dev, &iommu_table_iobmap);190}191192static int __init iob_init(struct device_node *dn)193{194unsigned long tmp;195u32 regword;196int i;197198pr_debug(" -> %s\n", __func__);199200/* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */201iob_l2_base = memblock_alloc_try_nid_raw(1UL << 21, 1UL << 21,202MEMBLOCK_LOW_LIMIT, 0x80000000,203NUMA_NO_NODE);204if (!iob_l2_base)205panic("%s: Failed to allocate %lu bytes align=0x%lx max_addr=%x\n",206__func__, 1UL << 21, 1UL << 21, 0x80000000);207208pr_info("IOBMAP L2 allocated at: %p\n", iob_l2_base);209210/* Allocate a spare page to map all invalid IOTLB pages. */211tmp = memblock_phys_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE);212if (!tmp)213panic("IOBMAP: Cannot allocate spare page!");214/* Empty l1 is marked invalid */215iob_l1_emptyval = 0;216/* Empty l2 is mapped to dummy page */217iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT);218219iob = ioremap(IOB_BASE, IOB_SIZE);220if (!iob)221panic("IOBMAP: Cannot map registers!");222223/* setup direct mapping of the L1 entries */224for (i = 0; i < 64; i++) {225/* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */226regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12);227out_le32(iob+IOB_XLT_L1_REGBASE+i*4, regword);228}229230/* set 2GB translation window, based at 0 */231regword = in_le32(iob+IOB_AD_REG);232regword &= ~IOB_AD_TRNG_MASK;233regword |= IOB_AD_TRNG_2G;234out_le32(iob+IOB_AD_REG, regword);235236/* Enable translation */237regword = in_le32(iob+IOBCOM_REG);238regword |= IOBCOM_ATEN;239out_le32(iob+IOBCOM_REG, regword);240241pr_debug(" <- %s\n", __func__);242243return 0;244}245246247/* These are called very early. */248void __init iommu_init_early_pasemi(void)249{250int iommu_off;251252#ifndef CONFIG_PPC_PASEMI_IOMMU253iommu_off = 1;254#else255iommu_off = of_chosen &&256of_property_read_bool(of_chosen, "linux,iommu-off");257#endif258if (iommu_off)259return;260261iob_init(NULL);262263pasemi_pci_controller_ops.dma_dev_setup = pci_dma_dev_setup_pasemi;264pasemi_pci_controller_ops.dma_bus_setup = pci_dma_bus_setup_pasemi;265set_pci_dma_ops(&dma_iommu_ops);266}267268269