Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.9.4.
 1/*
 2 * Re-map IO memory to kernel address space so that we can access it.
 3 * This is needed for high PCI addresses that aren't mapped in the
 4 * 640k-1MB IO memory area on PC's
 5 *
 6 * (C) Copyright 1995 1996 Linus Torvalds
 7 */
 8#include <linux/vmalloc.h>
 9#include <linux/mm.h>
10#include <linux/sched.h>
11#include <linux/io.h>
12#include <linux/export.h>
13#include <asm/cacheflush.h>
14#include <asm/pgtable.h>
15
16static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
17		unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
18{
19	pte_t *pte;
20	u64 pfn;
21
22	pfn = phys_addr >> PAGE_SHIFT;
23	pte = pte_alloc_kernel(pmd, addr);
24	if (!pte)
25		return -ENOMEM;
26	do {
27		BUG_ON(!pte_none(*pte));
28		set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
29		pfn++;
30	} while (pte++, addr += PAGE_SIZE, addr != end);
31	return 0;
32}
33
34static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
35		unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
36{
37	pmd_t *pmd;
38	unsigned long next;
39
40	phys_addr -= addr;
41	pmd = pmd_alloc(&init_mm, pud, addr);
42	if (!pmd)
43		return -ENOMEM;
44	do {
45		next = pmd_addr_end(addr, end);
46		if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
47			return -ENOMEM;
48	} while (pmd++, addr = next, addr != end);
49	return 0;
50}
51
52static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
53		unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
54{
55	pud_t *pud;
56	unsigned long next;
57
58	phys_addr -= addr;
59	pud = pud_alloc(&init_mm, pgd, addr);
60	if (!pud)
61		return -ENOMEM;
62	do {
63		next = pud_addr_end(addr, end);
64		if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
65			return -ENOMEM;
66	} while (pud++, addr = next, addr != end);
67	return 0;
68}
69
70int ioremap_page_range(unsigned long addr,
71		       unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
72{
73	pgd_t *pgd;
74	unsigned long start;
75	unsigned long next;
76	int err;
77
78	BUG_ON(addr >= end);
79
80	start = addr;
81	phys_addr -= addr;
82	pgd = pgd_offset_k(addr);
83	do {
84		next = pgd_addr_end(addr, end);
85		err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
86		if (err)
87			break;
88	} while (pgd++, addr = next, addr != end);
89
90	flush_cache_vmap(start, end);
91
92	return err;
93}
94EXPORT_SYMBOL_GPL(ioremap_page_range);