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 #ifndef	_LINUXKPI_LINUX_IO_H_
30 #define	_LINUXKPI_LINUX_IO_H_
31 
32 #include <sys/endian.h>
33 #include <sys/types.h>
34 
35 #include <machine/vm.h>
36 
37 #include <linux/compiler.h>
38 #include <linux/types.h>
39 #if !defined(__arm__)
40 #include <asm/set_memory.h>
41 #endif
42 
43 /*
44  * XXX This is all x86 specific.  It should be bus space access.
45  */
46 
47 /* rmb and wmb are declared in machine/atomic.h, so should be included first. */
48 #ifndef __io_br
49 #define	__io_br()	__compiler_membar()
50 #endif
51 
52 #ifndef __io_ar
53 #ifdef rmb
54 #define	__io_ar()	rmb()
55 #else
56 #define	__io_ar()	__compiler_membar()
57 #endif
58 #endif
59 
60 #ifndef __io_bw
61 #ifdef wmb
62 #define	__io_bw()	wmb()
63 #else
64 #define	__io_bw()	__compiler_membar()
65 #endif
66 #endif
67 
68 #ifndef __io_aw
69 #define	__io_aw()	__compiler_membar()
70 #endif
71 
72 /* Access MMIO registers atomically without barriers and byte swapping. */
73 
74 static inline uint8_t
75 __raw_readb(const volatile void *addr)
76 {
77 	return (*(const volatile uint8_t *)addr);
78 }
79 #define	__raw_readb(addr)	__raw_readb(addr)
80 
81 static inline void
82 __raw_writeb(uint8_t v, volatile void *addr)
83 {
84 	*(volatile uint8_t *)addr = v;
85 }
86 #define	__raw_writeb(v, addr)	__raw_writeb(v, addr)
87 
88 static inline uint16_t
89 __raw_readw(const volatile void *addr)
90 {
91 	return (*(const volatile uint16_t *)addr);
92 }
93 #define	__raw_readw(addr)	__raw_readw(addr)
94 
95 static inline void
96 __raw_writew(uint16_t v, volatile void *addr)
97 {
98 	*(volatile uint16_t *)addr = v;
99 }
100 #define	__raw_writew(v, addr)	__raw_writew(v, addr)
101 
102 static inline uint32_t
103 __raw_readl(const volatile void *addr)
104 {
105 	return (*(const volatile uint32_t *)addr);
106 }
107 #define	__raw_readl(addr)	__raw_readl(addr)
108 
109 static inline void
110 __raw_writel(uint32_t v, volatile void *addr)
111 {
112 	*(volatile uint32_t *)addr = v;
113 }
114 #define	__raw_writel(v, addr)	__raw_writel(v, addr)
115 
116 #ifdef __LP64__
117 static inline uint64_t
118 __raw_readq(const volatile void *addr)
119 {
120 	return (*(const volatile uint64_t *)addr);
121 }
122 #define	__raw_readq(addr)	__raw_readq(addr)
123 
124 static inline void
125 __raw_writeq(uint64_t v, volatile void *addr)
126 {
127 	*(volatile uint64_t *)addr = v;
128 }
129 #define	__raw_writeq(v, addr)	__raw_writeq(v, addr)
130 #endif
131 
132 #define	mmiowb()	barrier()
133 
134 /* Access little-endian MMIO registers atomically with memory barriers. */
135 
136 #undef readb
137 static inline uint8_t
138 readb(const volatile void *addr)
139 {
140 	uint8_t v;
141 
142 	__io_br();
143 	v = *(const volatile uint8_t *)addr;
144 	__io_ar();
145 	return (v);
146 }
147 #define	readb(addr)		readb(addr)
148 
149 #undef writeb
150 static inline void
151 writeb(uint8_t v, volatile void *addr)
152 {
153 	__io_bw();
154 	*(volatile uint8_t *)addr = v;
155 	__io_aw();
156 }
157 #define	writeb(v, addr)		writeb(v, addr)
158 
159 #undef readw
160 static inline uint16_t
161 readw(const volatile void *addr)
162 {
163 	uint16_t v;
164 
165 	__io_br();
166 	v = le16toh(__raw_readw(addr));
167 	__io_ar();
168 	return (v);
169 }
170 #define	readw(addr)		readw(addr)
171 
172 #undef writew
173 static inline void
174 writew(uint16_t v, volatile void *addr)
175 {
176 	__io_bw();
177 	__raw_writew(htole16(v), addr);
178 	__io_aw();
179 }
180 #define	writew(v, addr)		writew(v, addr)
181 
182 #undef readl
183 static inline uint32_t
184 readl(const volatile void *addr)
185 {
186 	uint32_t v;
187 
188 	__io_br();
189 	v = le32toh(__raw_readl(addr));
190 	__io_ar();
191 	return (v);
192 }
193 #define	readl(addr)		readl(addr)
194 
195 #undef writel
196 static inline void
197 writel(uint32_t v, volatile void *addr)
198 {
199 	__io_bw();
200 	__raw_writel(htole32(v), addr);
201 	__io_aw();
202 }
203 #define	writel(v, addr)		writel(v, addr)
204 
205 #undef readq
206 #undef writeq
207 #ifdef __LP64__
208 static inline uint64_t
209 readq(const volatile void *addr)
210 {
211 	uint64_t v;
212 
213 	__io_br();
214 	v = le64toh(__raw_readq(addr));
215 	__io_ar();
216 	return (v);
217 }
218 #define	readq(addr)		readq(addr)
219 
220 static inline void
221 writeq(uint64_t v, volatile void *addr)
222 {
223 	__io_bw();
224 	__raw_writeq(htole64(v), addr);
225 	__io_aw();
226 }
227 #define	writeq(v, addr)		writeq(v, addr)
228 #endif
229 
230 /* Access little-endian MMIO registers atomically without memory barriers. */
231 
232 #undef readb_relaxed
233 static inline uint8_t
234 readb_relaxed(const volatile void *addr)
235 {
236 	return (__raw_readb(addr));
237 }
238 #define	readb_relaxed(addr)	readb_relaxed(addr)
239 
240 #undef writeb_relaxed
241 static inline void
242 writeb_relaxed(uint8_t v, volatile void *addr)
243 {
244 	__raw_writeb(v, addr);
245 }
246 #define	writeb_relaxed(v, addr)	writeb_relaxed(v, addr)
247 
248 #undef readw_relaxed
249 static inline uint16_t
250 readw_relaxed(const volatile void *addr)
251 {
252 	return (le16toh(__raw_readw(addr)));
253 }
254 #define	readw_relaxed(addr)	readw_relaxed(addr)
255 
256 #undef writew_relaxed
257 static inline void
258 writew_relaxed(uint16_t v, volatile void *addr)
259 {
260 	__raw_writew(htole16(v), addr);
261 }
262 #define	writew_relaxed(v, addr)	writew_relaxed(v, addr)
263 
264 #undef readl_relaxed
265 static inline uint32_t
266 readl_relaxed(const volatile void *addr)
267 {
268 	return (le32toh(__raw_readl(addr)));
269 }
270 #define	readl_relaxed(addr)	readl_relaxed(addr)
271 
272 #undef writel_relaxed
273 static inline void
274 writel_relaxed(uint32_t v, volatile void *addr)
275 {
276 	__raw_writel(htole32(v), addr);
277 }
278 #define	writel_relaxed(v, addr)	writel_relaxed(v, addr)
279 
280 #undef readq_relaxed
281 #undef writeq_relaxed
282 #ifdef __LP64__
283 static inline uint64_t
284 readq_relaxed(const volatile void *addr)
285 {
286 	return (le64toh(__raw_readq(addr)));
287 }
288 #define	readq_relaxed(addr)	readq_relaxed(addr)
289 
290 static inline void
291 writeq_relaxed(uint64_t v, volatile void *addr)
292 {
293 	__raw_writeq(htole64(v), addr);
294 }
295 #define	writeq_relaxed(v, addr)	writeq_relaxed(v, addr)
296 #endif
297 
298 /* XXX On Linux ioread and iowrite handle both MMIO and port IO. */
299 
300 #undef ioread8
301 static inline uint8_t
302 ioread8(const volatile void *addr)
303 {
304 	return (readb(addr));
305 }
306 #define	ioread8(addr)		ioread8(addr)
307 
308 #undef ioread16
309 static inline uint16_t
310 ioread16(const volatile void *addr)
311 {
312 	return (readw(addr));
313 }
314 #define	ioread16(addr)		ioread16(addr)
315 
316 #undef ioread16be
317 static inline uint16_t
318 ioread16be(const volatile void *addr)
319 {
320 	uint16_t v;
321 
322 	__io_br();
323 	v = (be16toh(__raw_readw(addr)));
324 	__io_ar();
325 
326 	return (v);
327 }
328 #define	ioread16be(addr)	ioread16be(addr)
329 
330 #undef ioread32
331 static inline uint32_t
332 ioread32(const volatile void *addr)
333 {
334 	return (readl(addr));
335 }
336 #define	ioread32(addr)		ioread32(addr)
337 
338 #undef ioread32be
339 static inline uint32_t
340 ioread32be(const volatile void *addr)
341 {
342 	uint32_t v;
343 
344 	__io_br();
345 	v = (be32toh(__raw_readl(addr)));
346 	__io_ar();
347 
348 	return (v);
349 }
350 #define	ioread32be(addr)	ioread32be(addr)
351 
352 #undef ioread64
353 static inline uint64_t
354 ioread64(const volatile void *addr)
355 {
356 	return (readq(addr));
357 }
358 #define	ioread64(addr)		ioread64(addr)
359 
360 #undef iowrite8
361 static inline void
362 iowrite8(uint8_t v, volatile void *addr)
363 {
364 	writeb(v, addr);
365 }
366 #define	iowrite8(v, addr)	iowrite8(v, addr)
367 
368 #undef iowrite16
369 static inline void
370 iowrite16(uint16_t v, volatile void *addr)
371 {
372 	writew(v, addr);
373 }
374 #define	iowrite16	iowrite16
375 
376 #undef iowrite32
377 static inline void
378 iowrite32(uint32_t v, volatile void *addr)
379 {
380 	writel(v, addr);
381 }
382 #define	iowrite32(v, addr)	iowrite32(v, addr)
383 
384 #undef iowrite32be
385 static inline void
386 iowrite32be(uint32_t v, volatile void *addr)
387 {
388 	__io_bw();
389 	__raw_writel(htobe32(v), addr);
390 	__io_aw();
391 }
392 #define	iowrite32be(v, addr)	iowrite32be(v, addr)
393 
394 #if defined(__i386__) || defined(__amd64__)
395 static inline void
396 _outb(u_char data, u_int port)
397 {
398 	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
399 }
400 #endif
401 
402 #if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__) || defined(__riscv)
403 void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr);
404 #else
405 static __inline void *
406 _ioremap_attr(vm_paddr_t _phys_addr, unsigned long _size, int _attr)
407 {
408 	return (NULL);
409 }
410 #endif
411 
412 struct device;
413 static inline void *
414 devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size)
415 {
416 	return (NULL);
417 }
418 
419 #ifdef VM_MEMATTR_DEVICE
420 #define	ioremap_nocache(addr, size)					\
421     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
422 #define	ioremap_wt(addr, size)						\
423     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
424 #define	ioremap(addr, size)						\
425     _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
426 #else
427 #define	ioremap_nocache(addr, size)					\
428     _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
429 #define	ioremap_wt(addr, size)						\
430     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_THROUGH)
431 #define	ioremap(addr, size)						\
432     _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
433 #endif
434 #ifdef VM_MEMATTR_WRITE_COMBINING
435 #define	ioremap_wc(addr, size)						\
436     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_COMBINING)
437 #else
438 #define	ioremap_wc(addr, size)	ioremap_nocache(addr, size)
439 #endif
440 #define	ioremap_cache(addr, size)					\
441     _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_BACK)
442 void iounmap(void *addr);
443 
444 #define	memset_io(a, b, c)	memset((a), (b), (c))
445 #define	memcpy_fromio(a, b, c)	memcpy((a), (b), (c))
446 #define	memcpy_toio(a, b, c)	memcpy((a), (b), (c))
447 
448 static inline void
449 __iowrite32_copy(void *to, const void *from, size_t count)
450 {
451 	const uint32_t *src;
452 	uint32_t *dst;
453 	int i;
454 
455 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
456 		__raw_writel(*src, dst);
457 }
458 
459 static inline void
460 __iowrite64_copy(void *to, const void *from, size_t count)
461 {
462 #ifdef __LP64__
463 	const uint64_t *src;
464 	uint64_t *dst;
465 	int i;
466 
467 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
468 		__raw_writeq(*src, dst);
469 #else
470 	__iowrite32_copy(to, from, count * 2);
471 #endif
472 }
473 
474 static inline void
475 __ioread32_copy(void *to, const void *from, size_t count)
476 {
477 	const uint32_t *src;
478 	uint32_t *dst;
479 	int i;
480 
481 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
482 		*dst = __raw_readl(src);
483 }
484 
485 static inline void
486 __ioread64_copy(void *to, const void *from, size_t count)
487 {
488 #ifdef __LP64__
489 	const uint64_t *src;
490 	uint64_t *dst;
491 	int i;
492 
493 	for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
494 		*dst = __raw_readq(src);
495 #else
496 	__ioread32_copy(to, from, count * 2);
497 #endif
498 }
499 
500 enum {
501 	MEMREMAP_WB = 1 << 0,
502 	MEMREMAP_WT = 1 << 1,
503 	MEMREMAP_WC = 1 << 2,
504 };
505 
506 static inline void *
507 memremap(resource_size_t offset, size_t size, unsigned long flags)
508 {
509 	void *addr = NULL;
510 
511 	if ((flags & MEMREMAP_WB) &&
512 	    (addr = ioremap_cache(offset, size)) != NULL)
513 		goto done;
514 	if ((flags & MEMREMAP_WT) &&
515 	    (addr = ioremap_wt(offset, size)) != NULL)
516 		goto done;
517 	if ((flags & MEMREMAP_WC) &&
518 	    (addr = ioremap_wc(offset, size)) != NULL)
519 		goto done;
520 done:
521 	return (addr);
522 }
523 
524 static inline void
525 memunmap(void *addr)
526 {
527 	/* XXX May need to check if this is RAM */
528 	iounmap(addr);
529 }
530 
531 #define	__MTRR_ID_BASE	1
532 int lkpi_arch_phys_wc_add(unsigned long, unsigned long);
533 void lkpi_arch_phys_wc_del(int);
534 #define	arch_phys_wc_add(...)	lkpi_arch_phys_wc_add(__VA_ARGS__)
535 #define	arch_phys_wc_del(...)	lkpi_arch_phys_wc_del(__VA_ARGS__)
536 #define	arch_phys_wc_index(x)	\
537 	(((x) < __MTRR_ID_BASE) ? -1 : ((x) - __MTRR_ID_BASE))
538 
539 #if defined(__amd64__) || defined(__i386__) || defined(__aarch64__) || defined(__powerpc__) || defined(__riscv)
540 static inline int
541 arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
542 {
543 	vm_offset_t va;
544 
545 	va = PHYS_TO_DMAP(start);
546 
547 #ifdef VM_MEMATTR_WRITE_COMBINING
548 	return (-pmap_change_attr(va, size, VM_MEMATTR_WRITE_COMBINING));
549 #else
550 	return (-pmap_change_attr(va, size, VM_MEMATTR_UNCACHEABLE));
551 #endif
552 }
553 
554 static inline void
555 arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
556 {
557 	vm_offset_t va;
558 
559 	va = PHYS_TO_DMAP(start);
560 
561 	pmap_change_attr(va, size, VM_MEMATTR_WRITE_BACK);
562 }
563 #endif
564 
565 #endif	/* _LINUXKPI_LINUX_IO_H_ */
566