Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// SPDX-License-Identifier: GPL-2.0
/*
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
*
* 1996: sparc_free_io, 1999: ioremap()/iounmap() by Pete Zaitcev.
*
* 2000/01/29
* <rth> zait: as long as pci_alloc_consistent produces something addressable,
* things are ok.
* <zaitcev> rth: no, it is relevant, because get_free_pages returns you a
* pointer into the big page mapping
* <rth> zait: so what?
* <rth> zait: remap_it_my_way(virt_to_phys(get_free_page()))
* <zaitcev> Hmm
* <zaitcev> Suppose I did this remap_it_my_way(virt_to_phys(get_free_page())).
* So far so good.
* <zaitcev> Now, driver calls pci_free_consistent(with result of
* remap_it_my_way()).
* <zaitcev> How do you find the address to pass to free_pages()?
* <rth> zait: walk the page tables? It's only two or three level after all.
* <rth> zait: you have to walk them anyway to remove the mapping.
* <zaitcev> Hmm
* <zaitcev> Sounds reasonable
*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/pci.h> /* struct pci_dev */
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/scatterlist.h>
#include <linux/dma-map-ops.h>
#include <linux/of_device.h>
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
#include <asm/iommu.h>
#include <asm/io-unit.h>
#include <asm/leon.h>
/* This function must make sure that caches and memory are coherent after DMA
* On LEON systems without cache snooping it flushes the entire D-CACHE.
*/
static inline void dma_make_coherent(unsigned long pa, unsigned long len)
{
<------>if (sparc_cpu_model == sparc_leon) {
<------><------>if (!sparc_leon3_snooping_enabled())
<------><------><------>leon_flush_dcache_all();
<------>}
}
static void __iomem *_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz);
static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
unsigned long size, char *name);
static void _sparc_free_io(struct resource *res);
static void register_proc_sparc_ioport(void);
/* This points to the next to use virtual memory for DVMA mappings */
static struct resource _sparc_dvma = {
<------>.name = "sparc_dvma", .start = DVMA_VADDR, .end = DVMA_END - 1
};
/* This points to the start of I/O mappings, cluable from outside. */
/*ext*/ struct resource sparc_iomap = {
<------>.name = "sparc_iomap", .start = IOBASE_VADDR, .end = IOBASE_END - 1
};
/*
* Our mini-allocator...
* Boy this is gross! We need it because we must map I/O for
* timers and interrupt controller before the kmalloc is available.
*/
#define XNMLN 15
#define XNRES 10 /* SS-10 uses 8 */
struct xresource {
<------>struct resource xres; /* Must be first */
<------>int xflag; /* 1 == used */
<------>char xname[XNMLN+1];
};
static struct xresource xresv[XNRES];
static struct xresource *xres_alloc(void) {
<------>struct xresource *xrp;
<------>int n;
<------>xrp = xresv;
<------>for (n = 0; n < XNRES; n++) {
<------><------>if (xrp->xflag == 0) {
<------><------><------>xrp->xflag = 1;
<------><------><------>return xrp;
<------><------>}
<------><------>xrp++;
<------>}
<------>return NULL;
}
static void xres_free(struct xresource *xrp) {
<------>xrp->xflag = 0;
}
/*
* These are typically used in PCI drivers
* which are trying to be cross-platform.
*
* Bus type is always zero on IIep.
*/
void __iomem *ioremap(phys_addr_t offset, size_t size)
{
<------>char name[14];
<------>sprintf(name, "phys_%08x", (u32)offset);
<------>return _sparc_alloc_io(0, (unsigned long)offset, size, name);
}
EXPORT_SYMBOL(ioremap);
/*
* Complementary to ioremap().
*/
void iounmap(volatile void __iomem *virtual)
{
<------>unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
<------>struct resource *res;
<------>/*
<------> * XXX Too slow. Can have 8192 DVMA pages on sun4m in the worst case.
<------> * This probably warrants some sort of hashing.
<------>*/
<------>if ((res = lookup_resource(&sparc_iomap, vaddr)) == NULL) {
<------><------>printk("free_io/iounmap: cannot free %lx\n", vaddr);
<------><------>return;
<------>}
<------>_sparc_free_io(res);
<------>if ((char *)res >= (char*)xresv && (char *)res < (char *)&xresv[XNRES]) {
<------><------>xres_free((struct xresource *)res);
<------>} else {
<------><------>kfree(res);
<------>}
}
EXPORT_SYMBOL(iounmap);
void __iomem *of_ioremap(struct resource *res, unsigned long offset,
<------><------><------> unsigned long size, char *name)
{
<------>return _sparc_alloc_io(res->flags & 0xF,
<------><------><------> res->start + offset,
<------><------><------> size, name);
}
EXPORT_SYMBOL(of_ioremap);
void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
{
<------>iounmap(base);
}
EXPORT_SYMBOL(of_iounmap);
/*
* Meat of mapping
*/
static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys,
unsigned long size, char *name)
{
<------>static int printed_full;
<------>struct xresource *xres;
<------>struct resource *res;
<------>char *tack;
<------>int tlen;
<------>void __iomem *va; /* P3 diag */
<------>if (name == NULL) name = "???";
<------>if ((xres = xres_alloc()) != NULL) {
<------><------>tack = xres->xname;
<------><------>res = &xres->xres;
<------>} else {
<------><------>if (!printed_full) {
<------><------><------>printk("ioremap: done with statics, switching to malloc\n");
<------><------><------>printed_full = 1;
<------><------>}
<------><------>tlen = strlen(name);
<------><------>tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL);
<------><------>if (tack == NULL) return NULL;
<------><------>memset(tack, 0, sizeof(struct resource));
<------><------>res = (struct resource *) tack;
<------><------>tack += sizeof (struct resource);
<------>}
<------>strlcpy(tack, name, XNMLN+1);
<------>res->name = tack;
<------>va = _sparc_ioremap(res, busno, phys, size);
<------>/* printk("ioremap(0x%x:%08lx[0x%lx])=%p\n", busno, phys, size, va); */ /* P3 diag */
<------>return va;
}
/*
*/
static void __iomem *
_sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz)
{
<------>unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
<------>if (allocate_resource(&sparc_iomap, res,
<------> (offset + sz + PAGE_SIZE-1) & PAGE_MASK,
<------> sparc_iomap.start, sparc_iomap.end, PAGE_SIZE, NULL, NULL) != 0) {
<------><------>/* Usually we cannot see printks in this case. */
<------><------>prom_printf("alloc_io_res(%s): cannot occupy\n",
<------><------> (res->name != NULL)? res->name: "???");
<------><------>prom_halt();
<------>}
<------>pa &= PAGE_MASK;
<------>srmmu_mapiorange(bus, pa, res->start, resource_size(res));
<------>return (void __iomem *)(unsigned long)(res->start + offset);
}
/*
* Complementary to _sparc_ioremap().
*/
static void _sparc_free_io(struct resource *res)
{
<------>unsigned long plen;
<------>plen = resource_size(res);
<------>BUG_ON((plen & (PAGE_SIZE-1)) != 0);
<------>srmmu_unmapiorange(res->start, plen);
<------>release_resource(res);
}
unsigned long sparc_dma_alloc_resource(struct device *dev, size_t len)
{
<------>struct resource *res;
<------>res = kzalloc(sizeof(*res), GFP_KERNEL);
<------>if (!res)
<------><------>return 0;
<------>res->name = dev->of_node->full_name;
<------>if (allocate_resource(&_sparc_dvma, res, len, _sparc_dvma.start,
<------><------><------> _sparc_dvma.end, PAGE_SIZE, NULL, NULL) != 0) {
<------><------>printk("%s: cannot occupy 0x%zx", __func__, len);
<------><------>kfree(res);
<------><------>return 0;
<------>}
<------>return res->start;
}
bool sparc_dma_free_resource(void *cpu_addr, size_t size)
{
<------>unsigned long addr = (unsigned long)cpu_addr;
<------>struct resource *res;
<------>res = lookup_resource(&_sparc_dvma, addr);
<------>if (!res) {
<------><------>printk("%s: cannot free %p\n", __func__, cpu_addr);
<------><------>return false;
<------>}
<------>if ((addr & (PAGE_SIZE - 1)) != 0) {
<------><------>printk("%s: unaligned va %p\n", __func__, cpu_addr);
<------><------>return false;
<------>}
<------>size = PAGE_ALIGN(size);
<------>if (resource_size(res) != size) {
<------><------>printk("%s: region 0x%lx asked 0x%zx\n",
<------><------><------>__func__, (long)resource_size(res), size);
<------><------>return false;
<------>}
<------>release_resource(res);
<------>kfree(res);
<------>return true;
}
#ifdef CONFIG_SBUS
void sbus_set_sbus64(struct device *dev, int x)
{
<------>printk("sbus_set_sbus64: unsupported\n");
}
EXPORT_SYMBOL(sbus_set_sbus64);
static int __init sparc_register_ioport(void)
{
<------>register_proc_sparc_ioport();
<------>return 0;
}
arch_initcall(sparc_register_ioport);
#endif /* CONFIG_SBUS */
/* Allocate and map kernel buffer using consistent mode DMA for a device.
* hwdev should be valid struct pci_dev pointer for PCI devices.
*/
void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
<------><------>gfp_t gfp, unsigned long attrs)
{
<------>unsigned long addr;
<------>void *va;
<------>if (!size || size > 256 * 1024) /* __get_free_pages() limit */
<------><------>return NULL;
<------>size = PAGE_ALIGN(size);
<------>va = (void *) __get_free_pages(gfp | __GFP_ZERO, get_order(size));
<------>if (!va) {
<------><------>printk("%s: no %zd pages\n", __func__, size >> PAGE_SHIFT);
<------><------>return NULL;
<------>}
<------>addr = sparc_dma_alloc_resource(dev, size);
<------>if (!addr)
<------><------>goto err_nomem;
<------>srmmu_mapiorange(0, virt_to_phys(va), addr, size);
<------>*dma_handle = virt_to_phys(va);
<------>return (void *)addr;
err_nomem:
<------>free_pages((unsigned long)va, get_order(size));
<------>return NULL;
}
/* Free and unmap a consistent DMA buffer.
* cpu_addr is what was returned arch_dma_alloc, size must be the same as what
* was passed into arch_dma_alloc, and likewise dma_addr must be the same as
* what *dma_ndler was set to.
*
* References to the memory and mappings associated with cpu_addr/dma_addr
* past this call are illegal.
*/
void arch_dma_free(struct device *dev, size_t size, void *cpu_addr,
<------><------>dma_addr_t dma_addr, unsigned long attrs)
{
<------>size = PAGE_ALIGN(size);
<------>if (!sparc_dma_free_resource(cpu_addr, size))
<------><------>return;
<------>dma_make_coherent(dma_addr, size);
<------>srmmu_unmapiorange((unsigned long)cpu_addr, size);
<------>free_pages((unsigned long)phys_to_virt(dma_addr), get_order(size));
}
/* IIep is write-through, not flushing on cpu to device transfer. */
void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
<------><------>enum dma_data_direction dir)
{
<------>if (dir != PCI_DMA_TODEVICE)
<------><------>dma_make_coherent(paddr, PAGE_ALIGN(size));
}
#ifdef CONFIG_PROC_FS
static int sparc_io_proc_show(struct seq_file *m, void *v)
{
<------>struct resource *root = m->private, *r;
<------>const char *nm;
<------>for (r = root->child; r != NULL; r = r->sibling) {
<------><------>if ((nm = r->name) == NULL) nm = "???";
<------><------>seq_printf(m, "%016llx-%016llx: %s\n",
<------><------><------><------>(unsigned long long)r->start,
<------><------><------><------>(unsigned long long)r->end, nm);
<------>}
<------>return 0;
}
#endif /* CONFIG_PROC_FS */
static void register_proc_sparc_ioport(void)
{
#ifdef CONFIG_PROC_FS
<------>proc_create_single_data("io_map", 0, NULL, sparc_io_proc_show,
<------><------><------>&sparc_iomap);
<------>proc_create_single_data("dvma_map", 0, NULL, sparc_io_proc_show,
<------><------><------>&_sparc_dvma);
#endif
}