Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: Device specific operations

This patch adds several definitions for device communication, including
I/O accessors and ioremap(). The __raw_* accessors are implemented as
inline asm to avoid compiler generation of post-indexed accesses (less
efficient to emulate in a virtualised environment).

Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Tony Lindgren <tony@atomide.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>

+466
+26
arch/arm64/include/asm/device.h
··· 1 + /* 2 + * Copyright (C) 2012 ARM Ltd. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + #ifndef __ASM_DEVICE_H 17 + #define __ASM_DEVICE_H 18 + 19 + struct dev_archdata { 20 + struct dma_map_ops *dma_ops; 21 + }; 22 + 23 + struct pdev_archdata { 24 + }; 25 + 26 + #endif
+34
arch/arm64/include/asm/fb.h
··· 1 + /* 2 + * Copyright (C) 2012 ARM Ltd. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 + */ 16 + #ifndef __ASM_FB_H_ 17 + #define __ASM_FB_H_ 18 + 19 + #include <linux/fb.h> 20 + #include <linux/fs.h> 21 + #include <asm/page.h> 22 + 23 + static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, 24 + unsigned long off) 25 + { 26 + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); 27 + } 28 + 29 + static inline int fb_is_primary_device(struct fb_info *info) 30 + { 31 + return 0; 32 + } 33 + 34 + #endif /* __ASM_FB_H_ */
+258
arch/arm64/include/asm/io.h
··· 1 + /* 2 + * Based on arch/arm/include/asm/io.h 3 + * 4 + * Copyright (C) 1996-2000 Russell King 5 + * Copyright (C) 2012 ARM Ltd. 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + #ifndef __ASM_IO_H 20 + #define __ASM_IO_H 21 + 22 + #ifdef __KERNEL__ 23 + 24 + #include <linux/types.h> 25 + 26 + #include <asm/byteorder.h> 27 + #include <asm/barrier.h> 28 + #include <asm/pgtable.h> 29 + 30 + /* 31 + * Generic IO read/write. These perform native-endian accesses. 32 + */ 33 + static inline void __raw_writeb(u8 val, volatile void __iomem *addr) 34 + { 35 + asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr)); 36 + } 37 + 38 + static inline void __raw_writew(u16 val, volatile void __iomem *addr) 39 + { 40 + asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr)); 41 + } 42 + 43 + static inline void __raw_writel(u32 val, volatile void __iomem *addr) 44 + { 45 + asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr)); 46 + } 47 + 48 + static inline void __raw_writeq(u64 val, volatile void __iomem *addr) 49 + { 50 + asm volatile("str %0, [%1]" : : "r" (val), "r" (addr)); 51 + } 52 + 53 + static inline u8 __raw_readb(const volatile void __iomem *addr) 54 + { 55 + u8 val; 56 + asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr)); 57 + return val; 58 + } 59 + 60 + static inline u16 __raw_readw(const volatile void __iomem *addr) 61 + { 62 + u16 val; 63 + asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr)); 64 + return val; 65 + } 66 + 67 + static inline u32 __raw_readl(const volatile void __iomem *addr) 68 + { 69 + u32 val; 70 + asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr)); 71 + return val; 72 + } 73 + 74 + static inline u64 __raw_readq(const volatile void __iomem *addr) 75 + { 76 + u64 val; 77 + asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr)); 78 + return val; 79 + } 80 + 81 + /* IO barriers */ 82 + #define __iormb() rmb() 83 + #define __iowmb() wmb() 84 + 85 + #define mmiowb() do { } while (0) 86 + 87 + /* 88 + * Relaxed I/O memory access primitives. These follow the Device memory 89 + * ordering rules but do not guarantee any ordering relative to Normal memory 90 + * accesses. 91 + */ 92 + #define readb_relaxed(c) ({ u8 __v = __raw_readb(c); __v; }) 93 + #define readw_relaxed(c) ({ u16 __v = le16_to_cpu((__force __le16)__raw_readw(c)); __v; }) 94 + #define readl_relaxed(c) ({ u32 __v = le32_to_cpu((__force __le32)__raw_readl(c)); __v; }) 95 + 96 + #define writeb_relaxed(v,c) ((void)__raw_writeb((v),(c))) 97 + #define writew_relaxed(v,c) ((void)__raw_writew((__force u16)cpu_to_le16(v),(c))) 98 + #define writel_relaxed(v,c) ((void)__raw_writel((__force u32)cpu_to_le32(v),(c))) 99 + 100 + /* 101 + * I/O memory access primitives. Reads are ordered relative to any 102 + * following Normal memory access. Writes are ordered relative to any prior 103 + * Normal memory access. 104 + */ 105 + #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) 106 + #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) 107 + #define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; }) 108 + 109 + #define writeb(v,c) ({ __iowmb(); writeb_relaxed((v),(c)); }) 110 + #define writew(v,c) ({ __iowmb(); writew_relaxed((v),(c)); }) 111 + #define writel(v,c) ({ __iowmb(); writel_relaxed((v),(c)); }) 112 + 113 + /* 114 + * I/O port access primitives. 115 + */ 116 + #define IO_SPACE_LIMIT 0xffff 117 + #define PCI_IOBASE ((void __iomem *)0xffffffbbfffe0000UL) 118 + 119 + static inline u8 inb(unsigned long addr) 120 + { 121 + return readb(addr + PCI_IOBASE); 122 + } 123 + 124 + static inline u16 inw(unsigned long addr) 125 + { 126 + return readw(addr + PCI_IOBASE); 127 + } 128 + 129 + static inline u32 inl(unsigned long addr) 130 + { 131 + return readl(addr + PCI_IOBASE); 132 + } 133 + 134 + static inline void outb(u8 b, unsigned long addr) 135 + { 136 + writeb(b, addr + PCI_IOBASE); 137 + } 138 + 139 + static inline void outw(u16 b, unsigned long addr) 140 + { 141 + writew(b, addr + PCI_IOBASE); 142 + } 143 + 144 + static inline void outl(u32 b, unsigned long addr) 145 + { 146 + writel(b, addr + PCI_IOBASE); 147 + } 148 + 149 + #define inb_p(addr) inb(addr) 150 + #define inw_p(addr) inw(addr) 151 + #define inl_p(addr) inl(addr) 152 + 153 + #define outb_p(x, addr) outb((x), (addr)) 154 + #define outw_p(x, addr) outw((x), (addr)) 155 + #define outl_p(x, addr) outl((x), (addr)) 156 + 157 + static inline void insb(unsigned long addr, void *buffer, int count) 158 + { 159 + u8 *buf = buffer; 160 + while (count--) 161 + *buf++ = __raw_readb(addr + PCI_IOBASE); 162 + } 163 + 164 + static inline void insw(unsigned long addr, void *buffer, int count) 165 + { 166 + u16 *buf = buffer; 167 + while (count--) 168 + *buf++ = __raw_readw(addr + PCI_IOBASE); 169 + } 170 + 171 + static inline void insl(unsigned long addr, void *buffer, int count) 172 + { 173 + u32 *buf = buffer; 174 + while (count--) 175 + *buf++ = __raw_readl(addr + PCI_IOBASE); 176 + } 177 + 178 + static inline void outsb(unsigned long addr, const void *buffer, int count) 179 + { 180 + const u8 *buf = buffer; 181 + while (count--) 182 + __raw_writeb(*buf++, addr + PCI_IOBASE); 183 + } 184 + 185 + static inline void outsw(unsigned long addr, const void *buffer, int count) 186 + { 187 + const u16 *buf = buffer; 188 + while (count--) 189 + __raw_writew(*buf++, addr + PCI_IOBASE); 190 + } 191 + 192 + static inline void outsl(unsigned long addr, const void *buffer, int count) 193 + { 194 + const u32 *buf = buffer; 195 + while (count--) 196 + __raw_writel(*buf++, addr + PCI_IOBASE); 197 + } 198 + 199 + #define insb_p(port,to,len) insb(port,to,len) 200 + #define insw_p(port,to,len) insw(port,to,len) 201 + #define insl_p(port,to,len) insl(port,to,len) 202 + 203 + #define outsb_p(port,from,len) outsb(port,from,len) 204 + #define outsw_p(port,from,len) outsw(port,from,len) 205 + #define outsl_p(port,from,len) outsl(port,from,len) 206 + 207 + /* 208 + * String version of I/O memory access operations. 209 + */ 210 + extern void __memcpy_fromio(void *, const volatile void __iomem *, size_t); 211 + extern void __memcpy_toio(volatile void __iomem *, const void *, size_t); 212 + extern void __memset_io(volatile void __iomem *, int, size_t); 213 + 214 + #define memset_io(c,v,l) __memset_io((c),(v),(l)) 215 + #define memcpy_fromio(a,c,l) __memcpy_fromio((a),(c),(l)) 216 + #define memcpy_toio(c,a,l) __memcpy_toio((c),(a),(l)) 217 + 218 + /* 219 + * I/O memory mapping functions. 220 + */ 221 + extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot); 222 + extern void __iounmap(volatile void __iomem *addr); 223 + 224 + #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY) 225 + #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) 226 + #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC)) 227 + 228 + #define ioremap(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) 229 + #define ioremap_nocache(addr, size) __ioremap((addr), (size), PROT_DEVICE_nGnRE) 230 + #define ioremap_wc(addr, size) __ioremap((addr), (size), PROT_NORMAL_NC) 231 + #define iounmap __iounmap 232 + 233 + #define ARCH_HAS_IOREMAP_WC 234 + #include <asm-generic/iomap.h> 235 + 236 + /* 237 + * More restrictive address range checking than the default implementation 238 + * (PHYS_OFFSET and PHYS_MASK taken into account). 239 + */ 240 + #define ARCH_HAS_VALID_PHYS_ADDR_RANGE 241 + extern int valid_phys_addr_range(unsigned long addr, size_t size); 242 + extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); 243 + 244 + extern int devmem_is_allowed(unsigned long pfn); 245 + 246 + /* 247 + * Convert a physical pointer to a virtual kernel pointer for /dev/mem 248 + * access 249 + */ 250 + #define xlate_dev_mem_ptr(p) __va(p) 251 + 252 + /* 253 + * Convert a virtual cached pointer to an uncached pointer 254 + */ 255 + #define xlate_dev_kmem_ptr(p) p 256 + 257 + #endif /* __KERNEL__ */ 258 + #endif /* __ASM_IO_H */
+64
arch/arm64/kernel/io.c
··· 1 + /* 2 + * Based on arch/arm/kernel/io.c 3 + * 4 + * Copyright (C) 2012 ARM Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License 16 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + 19 + #include <linux/export.h> 20 + #include <linux/types.h> 21 + #include <linux/io.h> 22 + 23 + /* 24 + * Copy data from IO memory space to "real" memory space. 25 + */ 26 + void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) 27 + { 28 + unsigned char *t = to; 29 + while (count) { 30 + count--; 31 + *t = readb(from); 32 + t++; 33 + from++; 34 + } 35 + } 36 + EXPORT_SYMBOL(__memcpy_fromio); 37 + 38 + /* 39 + * Copy data from "real" memory space to IO memory space. 40 + */ 41 + void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count) 42 + { 43 + const unsigned char *f = from; 44 + while (count) { 45 + count--; 46 + writeb(*f, to); 47 + f++; 48 + to++; 49 + } 50 + } 51 + EXPORT_SYMBOL(__memcpy_toio); 52 + 53 + /* 54 + * "memset" on IO memory space. 55 + */ 56 + void __memset_io(volatile void __iomem *dst, int c, size_t count) 57 + { 58 + while (count) { 59 + count--; 60 + writeb(c, dst); 61 + dst++; 62 + } 63 + } 64 + EXPORT_SYMBOL(__memset_io);
+84
arch/arm64/mm/ioremap.c
··· 1 + /* 2 + * Based on arch/arm/mm/ioremap.c 3 + * 4 + * (C) Copyright 1995 1996 Linus Torvalds 5 + * Hacked for ARM by Phil Blundell <philb@gnu.org> 6 + * Hacked to allow all architectures to build, and various cleanups 7 + * by Russell King 8 + * Copyright (C) 2012 ARM Ltd. 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + * 14 + * This program is distributed in the hope that it will be useful, 15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 + * GNU General Public License for more details. 18 + * 19 + * You should have received a copy of the GNU General Public License 20 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 21 + */ 22 + 23 + #include <linux/export.h> 24 + #include <linux/mm.h> 25 + #include <linux/vmalloc.h> 26 + #include <linux/io.h> 27 + 28 + static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, 29 + pgprot_t prot, void *caller) 30 + { 31 + unsigned long last_addr; 32 + unsigned long offset = phys_addr & ~PAGE_MASK; 33 + int err; 34 + unsigned long addr; 35 + struct vm_struct *area; 36 + 37 + /* 38 + * Page align the mapping address and size, taking account of any 39 + * offset. 40 + */ 41 + phys_addr &= PAGE_MASK; 42 + size = PAGE_ALIGN(size + offset); 43 + 44 + /* 45 + * Don't allow wraparound, zero size or outside PHYS_MASK. 46 + */ 47 + last_addr = phys_addr + size - 1; 48 + if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK)) 49 + return NULL; 50 + 51 + /* 52 + * Don't allow RAM to be mapped. 53 + */ 54 + if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr)))) 55 + return NULL; 56 + 57 + area = get_vm_area_caller(size, VM_IOREMAP, caller); 58 + if (!area) 59 + return NULL; 60 + addr = (unsigned long)area->addr; 61 + 62 + err = ioremap_page_range(addr, addr + size, phys_addr, prot); 63 + if (err) { 64 + vunmap((void *)addr); 65 + return NULL; 66 + } 67 + 68 + return (void __iomem *)(offset + addr); 69 + } 70 + 71 + void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot) 72 + { 73 + return __ioremap_caller(phys_addr, size, prot, 74 + __builtin_return_address(0)); 75 + } 76 + EXPORT_SYMBOL(__ioremap); 77 + 78 + void __iounmap(volatile void __iomem *io_addr) 79 + { 80 + void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); 81 + 82 + vunmap(addr); 83 + } 84 + EXPORT_SYMBOL(__iounmap);