1 /*-
2  * Copyright (c) 2010 Isilon Systems, Inc.
3  * Copyright (c) 2010 iX Systems, Inc.
4  * Copyright (c) 2010 Panasas, Inc.
5  * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #ifndef	_LINUX_IO_H_
32 #define	_LINUX_IO_H_
33 
34 #include <machine/vm.h>
35 #include <sys/endian.h>
36 #include <sys/types.h>
37 
38 #include <linux/compiler.h>
39 #include <linux/types.h>
40 
41 /*
42  * XXX This is all x86 specific.  It should be bus space access.
43  */
44 
45 
46 /* rmb and wmb are declared in machine/atomic.h, so should be included first. */
47 #ifndef __io_br
48 #define	__io_br()	__compiler_membar()
49 #endif
50 
51 #ifndef __io_ar
52 #ifdef rmb
53 #define	__io_ar()	rmb()
54 #else
55 #define	__io_ar()	__compiler_membar()
56 #endif
57 #endif
58 
59 #ifndef __io_bw
60 #ifdef wmb
61 #define	__io_bw()	wmb()
62 #else
63 #define	__io_bw()	__compiler_membar()
64 #endif
65 #endif
66 
67 #ifndef __io_aw
68 #define	__io_aw()	__compiler_membar()
69 #endif
70 
71 /* Access MMIO registers atomically without barriers and byte swapping. */
72 
73 static inline uint8_t
74 __raw_readb(const volatile void *addr)
75 {
76 	return (*(const volatile uint8_t *)addr);
77 }
78 #define	__raw_readb(addr)	__raw_readb(addr)
79 
80 static inline void
81 __raw_writeb(uint8_t v, volatile void *addr)
82 {
83 	*(volatile uint8_t *)addr = v;
84 }
85 #define	__raw_writeb(v, addr)	__raw_writeb(v, addr)
86 
87 static inline uint16_t
88 __raw_readw(const volatile void *addr)
89 {
90 	return (*(const volatile uint16_t *)addr);
91 }
92 #define	__raw_readw(addr)	__raw_readw(addr)
93 
94 static inline void
95 __raw_writew(uint16_t v, volatile void *addr)
96 {
97 	*(volatile uint16_t *)addr = v;
98 }
99 #define	__raw_writew(v, addr)	__raw_writew(v, addr)
100 
101 static inline uint32_t
102 __raw_readl(const volatile void *addr)
103 {
104 	return (*(const volatile uint32_t *)addr);
105 }
106 #define	__raw_readl(addr)	__raw_readl(addr)
107 
108 static inline void
109 __raw_writel(uint32_t v, volatile void *addr)
110 {
111 	*(volatile uint32_t *)addr = v;
112 }
113 #define	__raw_writel(v, addr)	__raw_writel(v, addr)
114 
115 #ifdef __LP64__
116 static inline uint64_t
117 __raw_readq(const volatile void *addr)
118 {
119 	return (*(const volatile uint64_t *)addr);
120 }
121 #define	__raw_readq(addr)	__raw_readq(addr)
122 
123 static inline void
124 __raw_writeq(uint64_t v, volatile void *addr)
125 {
126 	*(volatile uint64_t *)addr = v;
127 }
128 #define	__raw_writeq(v, addr)	__raw_writeq(v, addr)
129 #endif
130 
131 #define	mmiowb()	barrier()
132 
133 /* Access little-endian MMIO registers atomically with memory barriers. */
134 
135 #undef readb
136 static inline uint8_t
137 readb(const volatile void *addr)
138 {
139 	uint8_t v;
140 
141 	__io_br();
142 	v = *(const volatile uint8_t *)addr;
143 	__io_ar();
144 	return (v);
145 }
146 #define	readb(addr)		readb(addr)
147 
148 #undef writeb
149 static inline void
150 writeb(uint8_t v, volatile void *addr)
151 {
152 	__io_bw();
153 	*(volatile uint8_t *)addr = v;
154 	__io_aw();
155 }
156 #define	writeb(v, addr)		writeb(v, addr)
157 
158 #undef readw
159 static inline uint16_t
160 readw(const volatile void *addr)
161 {
162 	uint16_t v;
163 
164 	__io_br();
165 	v = le16toh(__raw_readw(addr));
166 	__io_ar();
167 	return (v);
168 }
169 #define	readw(addr)		readw(addr)
170 
171 #undef writew
172 static inline void
173 writew(uint16_t v, volatile void *addr)
174 {
175 	__io_bw();
176 	__raw_writew(htole16(v), addr);
177 	__io_aw();
178 }
179 #define	writew(v, addr)		writew(v, addr)
180 
181 #undef readl
182 static inline uint32_t
183 readl(const volatile void *addr)
184 {
185 	uint32_t v;
186 
187 	__io_br();
188 	v = le32toh(__raw_readl(addr));
189 	__io_ar();
190 	return (v);
191 }
192 #define	readl(addr)		readl(addr)
193 
194 #undef writel
195 static inline void
196 writel(uint32_t v, volatile void *addr)
197 {
198 	__io_bw();
199 	__raw_writel(htole32(v), addr);
200 	__io_aw();
201 }
202 #define	writel(v, addr)		writel(v, addr)
203 
204 #undef readq
205 #undef writeq
206 #ifdef __LP64__
207 static inline uint64_t
208 readq(const volatile void *addr)
209 {
210 	uint64_t v;
211 
212 	__io_br();
213 	v = le64toh(__raw_readq(addr));
214 	__io_ar();
215 	return (v);
216 }
217 #define	readq(addr)		readq(addr)
218 
219 static inline void
220 writeq(uint64_t v, volatile void *addr)
221 {
222 	__io_bw();
223 	__raw_writeq(htole64(v), addr);
224 	__io_aw();
225 }
226 #define	writeq(v, addr)		writeq(v, addr)
227 #endif
228 
229 /* Access little-endian MMIO registers atomically without memory barriers. */
230 
231 #undef readb_relaxed
232 static inline uint8_t
233 readb_relaxed(const volatile void *addr)
234 {
235 	return (__raw_readb(addr));
236 }
237 #define	readb_relaxed(addr)	readb_relaxed(addr)
238 
239 #undef writeb_relaxed
240 static inline void
241 writeb_relaxed(uint8_t v, volatile void *addr)
242 {
243 	__raw_writeb(v, addr);
244 }
245 #define	writeb_relaxed(v, addr)	writeb_relaxed(v, addr)
246 
247 #undef readw_relaxed
248 static inline uint16_t
249 readw_relaxed(const volatile void *addr)
250 {
251 	return (le16toh(__raw_readw(addr)));
252 }
253 #define	readw_relaxed(addr)	readw_relaxed(addr)
254 
255 #undef writew_relaxed
256 static inline void
257 writew_relaxed(uint16_t v, volatile void *addr)
258 {
259 	__raw_writew(htole16(v), addr);
260 }
261 #define	writew_relaxed(v, addr)	writew_relaxed(v, addr)
262 
263 #undef readl_relaxed
264 static inline uint32_t
265 readl_relaxed(const volatile void *addr)
266 {
267 	return (le32toh(__raw_readl(addr)));
268 }
269 #define	readl_relaxed(addr)	readl_relaxed(addr)
270 
271 #undef writel_relaxed
272 static inline void
273 writel_relaxed(uint32_t v, volatile void *addr)
274 {
275 	__raw_writel(htole32(v), addr);
276 }
277 #define	writel_relaxed(v, addr)	writel_relaxed(v, addr)
278 
279 #undef readq_relaxed
280 #undef writeq_relaxed
281 #ifdef __LP64__
282 static inline uint64_t
283 readq_relaxed(const volatile void *addr)
284 {
285 	return (le64toh(__raw_readq(addr)));
286 }
287 #define	readq_relaxed(addr)	readq_relaxed(addr)
288 
289 static inline void
290 writeq_relaxed(uint64_t v, volatile void *addr)
291 {
292 	__raw_writeq(htole64(v), addr);
293 }
294 #define	writeq_relaxed(v, addr)	writeq_relaxed(v, addr)
295 #endif
296 
297 /* XXX On Linux ioread and iowrite handle both MMIO and port IO. */
298 
299 #undef ioread8
300 static inline uint8_t
301 ioread8(const volatile void *addr)
302 {
303 	return (readb(addr));
304 }
305 #define	ioread8(addr)		ioread8(addr)
306 
307 #undef ioread16
308 static inline uint16_t
309 ioread16(const volatile void *addr)
310 {
311 	return (readw(addr));
312 }
313 #define	ioread16(addr)		ioread16(addr)
314 
315 #undef ioread16be
316 static inline uint16_t
317 ioread16be(const volatile void *addr)
318 {
319 	uint16_t v;
320 
321 	__io_br();
322 	v = (be16toh(__raw_readw(addr)));
323 	__io_ar();
324 
325 	return (v);
326 }
327 #define	ioread16be(addr)	ioread16be(addr)
328 
329 #undef ioread32
330 static inline uint32_t
331 ioread32(const volatile void *addr)
332 {
333 	return (readl(addr));
334 }
335 #define	ioread32(addr)		ioread32(addr)
336 
337 #undef ioread32be
338 static inline uint32_t
339 ioread32be(const volatile void *addr)
340 {
341 	uint32_t v;
342 
343 	__io_br();
344 	v = (be32toh(__raw_readl(addr)));
345 	__io_ar();
346 
347 	return (v);
348 }
349 #define	ioread32be(addr)	ioread32be(addr)
350 
351 #undef iowrite8
352 static inline void
353 iowrite8(uint8_t v, volatile void *addr)
354 {
355 	writeb(v, addr);
356 }
357 #define	iowrite8(v, addr)	iowrite8(v, addr)
358 
359 #undef iowrite16
360 static inline void
361 iowrite16(uint16_t v, volatile void *addr)
362 {
363 	writew(v, addr);
364 }
365 #define	iowrite16	iowrite16
366 
367 #undef iowrite32
368 static inline void
369 iowrite32(uint32_t v, volatile void *addr)
370 {
371 	writel(v, addr);
372 }
373 #define	iowrite32(v, addr)	iowrite32(v, addr)
374 
375 #undef iowrite32be
376 static inline void
377 iowrite32be(uint32_t v, volatile void *addr)
378 {
379 	__io_bw();
380 	__raw_writel(htobe32(v), addr);
381 	__io_aw();
382 }
383 #define	iowrite32be(v, addr)	iowrite32be(v, addr)
384 
385 #if defined(__i386__) || defined(__amd64__)
386 static inline void
387 _outb(u_char data, u_int port)
388 {
389 	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
390 }
391 #endif
392 
393 #if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__)
394 void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr);
395 #else
396 #define	_ioremap_attr(...) NULL
397 #endif
398 
399 #ifdef VM_MEMATTR_DEVICE
400 #define	ioremap_nocache(addr, size)					\
401     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
402 #define	ioremap_wt(addr, size)						\
403     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
404 #define	ioremap(addr, size)						\
405     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
406 #else
407 #define	ioremap_nocache(addr, size)					\
408     _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
409 #define	ioremap_wt(addr, size)						\
410     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_THROUGH)
411 #define	ioremap(addr, size)						\
412     _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
413 #endif
414 #define	ioremap_wc(addr, size)						\
415     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_COMBINING)
416 #define	ioremap_wb(addr, size)						\
417     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_BACK)
418 void iounmap(void *addr);
419 
420 #define	memset_io(a, b, c)	memset((a), (b), (c))
421 #define	memcpy_fromio(a, b, c)	memcpy((a), (b), (c))
422 #define	memcpy_toio(a, b, c)	memcpy((a), (b), (c))
423 
424 static inline void
425 __iowrite32_copy(void *to, void *from, size_t count)
426 {
427 	uint32_t *src;
428 	uint32_t *dst;
429 	int i;
430 
431 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
432 		__raw_writel(*src, dst);
433 }
434 
435 static inline void
436 __iowrite64_copy(void *to, void *from, size_t count)
437 {
438 #ifdef __LP64__
439 	uint64_t *src;
440 	uint64_t *dst;
441 	int i;
442 
443 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
444 		__raw_writeq(*src, dst);
445 #else
446 	__iowrite32_copy(to, from, count * 2);
447 #endif
448 }
449 
450 enum {
451 	MEMREMAP_WB = 1 << 0,
452 	MEMREMAP_WT = 1 << 1,
453 	MEMREMAP_WC = 1 << 2,
454 };
455 
456 static inline void *
457 memremap(resource_size_t offset, size_t size, unsigned long flags)
458 {
459 	void *addr = NULL;
460 
461 	if ((flags & MEMREMAP_WB) &&
462 	    (addr = ioremap_wb(offset, size)) != NULL)
463 		goto done;
464 	if ((flags & MEMREMAP_WT) &&
465 	    (addr = ioremap_wt(offset, size)) != NULL)
466 		goto done;
467 	if ((flags & MEMREMAP_WC) &&
468 	    (addr = ioremap_wc(offset, size)) != NULL)
469 		goto done;
470 done:
471 	return (addr);
472 }
473 
474 static inline void
475 memunmap(void *addr)
476 {
477 	/* XXX May need to check if this is RAM */
478 	iounmap(addr);
479 }
480 
481 #endif	/* _LINUX_IO_H_ */
482