/* * iommu.c: IOMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995,2002 Pete Zaitcev (zaitcev@yahoo.com) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/highmem.h> /* pte_offset_map => kmap_atomic */ #include <linux/scatterlist.h> #include <linux/of.h> #include <linux/of_device.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> #include <asm/io.h> #include <asm/mxcc.h> #include <asm/mbus.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <asm/bitext.h> #include <asm/iommu.h> #include <asm/dma.h> #include "mm_32.h" /* * This can be sized dynamically, but we will do this * only when we have a guidance about actual I/O pressures. */ #define IOMMU_RNGE IOMMU_RNGE_256MB #define IOMMU_START 0xF0000000 #define IOMMU_WINSIZE (256*1024*1024U) #define IOMMU_NPTES (IOMMU_WINSIZE/PAGE_SIZE) /* 64K PTEs, 256KB */ #define IOMMU_ORDER 6 /* 4096 * (1<<6) */ static int viking_flush; /* viking.S */ extern void viking_flush_page(unsigned long page); extern void viking_mxcc_flush_page(unsigned long page); /* * Values precomputed according to CPU type. */ static unsigned int ioperm_noc; /* Consistent mapping iopte flags */ static pgprot_t dvma_prot; /* Consistent mapping pte flags */ #define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ) static void __init sbus_iommu_init(struct platform_device *op) { struct iommu_struct *iommu; unsigned int impl, vers; unsigned long *bitmap; unsigned long control; unsigned long base; unsigned long tmp; iommu = kmalloc(sizeof(struct iommu_struct), GFP_KERNEL); if (!iommu) { prom_printf("Unable to allocate iommu structure\n"); prom_halt(); } iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3, "iommu_regs"); if (!iommu->regs) { prom_printf("Cannot map IOMMU registers\n"); prom_halt(); } control = sbus_readl(&iommu->regs->control); impl = (control & IOMMU_CTRL_IMPL) >> 28; vers = (control & IOMMU_CTRL_VERS) >> 24; control &= ~(IOMMU_CTRL_RNGE); control |= (IOMMU_RNGE_256MB | IOMMU_CTRL_ENAB); sbus_writel(control, &iommu->regs->control); iommu_invalidate(iommu->regs); iommu->start = IOMMU_START; iommu->end = 0xffffffff; /* Allocate IOMMU page table */ /* Stupid alignment constraints give me a headache. We need 256K or 512K or 1M or 2M area aligned to its size and current gfp will fortunately give it to us. */ tmp = __get_free_pages(GFP_KERNEL, IOMMU_ORDER); if (!tmp) { prom_printf("Unable to allocate iommu table [0x%lx]\n", IOMMU_NPTES * sizeof(iopte_t)); prom_halt(); } iommu->page_table = (iopte_t *)tmp; /* Initialize new table. */ memset(iommu->page_table, 0, IOMMU_NPTES*sizeof(iopte_t)); flush_cache_all(); flush_tlb_all(); base = __pa((unsigned long)iommu->page_table) >> 4; sbus_writel(base, &iommu->regs->base); iommu_invalidate(iommu->regs); bitmap = kmalloc(IOMMU_NPTES>>3, GFP_KERNEL); if (!bitmap) { prom_printf("Unable to allocate iommu bitmap [%d]\n", (int)(IOMMU_NPTES>>3)); prom_halt(); } bit_map_init(&iommu->usemap, bitmap, IOMMU_NPTES); /* To be coherent on HyperSparc, the page color of DVMA * and physical addresses must match. */ if (srmmu_modtype == HyperSparc) iommu->usemap.num_colors = vac_cache_size >> PAGE_SHIFT; else iommu->usemap.num_colors = 1; printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n", impl, vers, iommu->page_table, (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES); op->dev.archdata.iommu = iommu; } static int __init iommu_init(void) { struct device_node *dp; for_each_node_by_name(dp, "iommu") { struct platform_device *op = of_find_device_by_node(dp); sbus_iommu_init(op); of_propagate_archdata(op); } return 0; } subsys_initcall(iommu_init); /* Flush the iotlb entries to ram. */ /* This could be better if we didn't have to flush whole pages. */ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) { unsigned long start; unsigned long end; start = (unsigned long)iopte; end = PAGE_ALIGN(start + niopte*sizeof(iopte_t)); start &= PAGE_MASK; if (viking_mxcc_present) { while(start < end) { viking_mxcc_flush_page(start); start += PAGE_SIZE; } } else if (viking_flush) { while(start < end) { viking_flush_page(start); start += PAGE_SIZE; } } else { while(start < end) { __flush_page_to_ram(start); start += PAGE_SIZE; } } } static u32 iommu_get_one(struct device *dev, struct page *page, <style>.highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span><span class="c">#</span> <span class="c"># Makefile for physical layer USB drivers</span> <span class="c">#</span> <span class="nv">obj-$(CONFIG_USB_PHY)</span> <span class="o">+=</span> phy.o <span class="nv">obj-$(CONFIG_OF)</span> <span class="o">+=</span> of.o <span class="c"># transceiver drivers, keep the list sorted</span> <span class="nv">obj-$(CONFIG_AB8500_USB)</span> <span class="o">+=</span> phy-ab8500-usb.o <span class="nv">obj-$(CONFIG_FSL_USB2_OTG)</span> <span class="o">+=</span> phy-fsl-usb.o <span class="nv">obj-$(CONFIG_ISP1301_OMAP)</span> <span class="o">+=</span> phy-isp1301-omap.o <span class="nv">obj-$(CONFIG_NOP_USB_XCEIV)</span> <span class="o">+=</span> phy-generic.o <span class="nv">obj-$(CONFIG_TAHVO_USB)</span> <span class="o">+=</span> phy-tahvo.o <span class="nv">obj-$(CONFIG_AM335X_CONTROL_USB)</span> <span class="o">+=</span> phy-am335x-control.o <span class="nv">obj-$(CONFIG_AM335X_PHY_USB)</span> <span class="o">+=</span> phy-am335x.o <span class="nv">obj-$(CONFIG_OMAP_OTG)</span> <span class="o">+=</span> phy-omap-otg.o <span class="nv">obj-$(CONFIG_SAMSUNG_USBPHY)</span> <span class="o">+=</span> phy-samsung-usb.o <span class="nv">obj-$(CONFIG_TWL6030_USB)</span> <span class="o">+=</span> phy-twl6030-usb.o <span class="nv">obj-$(CONFIG_USB_EHCI_TEGRA)</span> <span class="o">+=</span> phy-tegra-usb.o <span class="nv">obj-$(CONFIG_USB_GPIO_VBUS)</span> <span class="o">+=</span> phy-gpio-vbus-usb.o <span class="nv">obj-$(CONFIG_USB_ISP1301)</span> <span class="o">+=</span> phy-isp1301.o <span class="nv">obj-$(CONFIG_USB_MSM_OTG)</span> <span class="o">+=</span> phy-msm-usb.o <span class="nv">obj-$(CONFIG_USB_QCOM_8X16_PHY)</span> <span class="o">+=</span> phy-qcom-8x16-usb.o <span class="nv">obj-$(CONFIG_USB_MV_OTG)</span> <span class="o">+=</span> phy-mv-usb.o <span class="nv">obj-$(CONFIG_USB_MXS_PHY)</span> <span class="o">+=</span> phy-mxs-usb.o <span class="nv">obj-$(CONFIG_USB_RCAR_PHY)</span> <span class="o">+=</span> phy-rcar-usb.o <span class="nv">obj-$(CONFIG_USB_ULPI)</span> <span class="o">+=</span> phy-ulpi.o <span class="nv">obj-$(CONFIG_USB_ULPI_VIEWPORT)</span> <span class="o">+=</span> phy-ulpi-viewport.o <span class="nv">obj-$(CONFIG_KEYSTONE_USB_PHY)</span> <span class="o">+=</span> phy-keystone.o </pre></div> </code></pre>