.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
---|
1 | 2 | #ifndef _ASM_POWERPC_IO_H |
---|
2 | 3 | #define _ASM_POWERPC_IO_H |
---|
3 | 4 | #ifdef __KERNEL__ |
---|
4 | 5 | |
---|
5 | 6 | #define ARCH_HAS_IOREMAP_WC |
---|
| 7 | +#ifdef CONFIG_PPC32 |
---|
| 8 | +#define ARCH_HAS_IOREMAP_WT |
---|
| 9 | +#endif |
---|
6 | 10 | |
---|
7 | 11 | /* |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License |
---|
10 | | - * as published by the Free Software Foundation; either version |
---|
11 | | - * 2 of the License, or (at your option) any later version. |
---|
12 | 12 | */ |
---|
13 | 13 | |
---|
14 | 14 | /* Check of existence of legacy devices */ |
---|
.. | .. |
---|
26 | 26 | |
---|
27 | 27 | #include <linux/device.h> |
---|
28 | 28 | #include <linux/compiler.h> |
---|
| 29 | +#include <linux/mm.h> |
---|
29 | 30 | #include <asm/page.h> |
---|
30 | 31 | #include <asm/byteorder.h> |
---|
31 | 32 | #include <asm/synch.h> |
---|
32 | 33 | #include <asm/delay.h> |
---|
| 34 | +#include <asm/mmiowb.h> |
---|
33 | 35 | #include <asm/mmu.h> |
---|
34 | 36 | #include <asm/ppc_asm.h> |
---|
35 | | - |
---|
36 | | -#ifdef CONFIG_PPC64 |
---|
37 | | -#include <asm/paca.h> |
---|
38 | | -#endif |
---|
39 | 37 | |
---|
40 | 38 | #define SIO_CONFIG_RA 0x398 |
---|
41 | 39 | #define SIO_CONFIG_RD 0x399 |
---|
.. | .. |
---|
102 | 100 | * |
---|
103 | 101 | */ |
---|
104 | 102 | |
---|
105 | | -#ifdef CONFIG_PPC64 |
---|
106 | | -#define IO_SET_SYNC_FLAG() do { local_paca->io_sync = 1; } while(0) |
---|
107 | | -#else |
---|
108 | | -#define IO_SET_SYNC_FLAG() |
---|
109 | | -#endif |
---|
110 | | - |
---|
111 | | -/* gcc 4.0 and older doesn't have 'Z' constraint */ |
---|
112 | | -#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0) |
---|
113 | | -#define DEF_MMIO_IN_X(name, size, insn) \ |
---|
114 | | -static inline u##size name(const volatile u##size __iomem *addr) \ |
---|
115 | | -{ \ |
---|
116 | | - u##size ret; \ |
---|
117 | | - __asm__ __volatile__("sync;"#insn" %0,0,%1;twi 0,%0,0;isync" \ |
---|
118 | | - : "=r" (ret) : "r" (addr), "m" (*addr) : "memory"); \ |
---|
119 | | - return ret; \ |
---|
120 | | -} |
---|
121 | | - |
---|
122 | | -#define DEF_MMIO_OUT_X(name, size, insn) \ |
---|
123 | | -static inline void name(volatile u##size __iomem *addr, u##size val) \ |
---|
124 | | -{ \ |
---|
125 | | - __asm__ __volatile__("sync;"#insn" %1,0,%2" \ |
---|
126 | | - : "=m" (*addr) : "r" (val), "r" (addr) : "memory"); \ |
---|
127 | | - IO_SET_SYNC_FLAG(); \ |
---|
128 | | -} |
---|
129 | | -#else /* newer gcc */ |
---|
130 | 103 | #define DEF_MMIO_IN_X(name, size, insn) \ |
---|
131 | 104 | static inline u##size name(const volatile u##size __iomem *addr) \ |
---|
132 | 105 | { \ |
---|
.. | .. |
---|
141 | 114 | { \ |
---|
142 | 115 | __asm__ __volatile__("sync;"#insn" %1,%y0" \ |
---|
143 | 116 | : "=Z" (*addr) : "r" (val) : "memory"); \ |
---|
144 | | - IO_SET_SYNC_FLAG(); \ |
---|
| 117 | + mmiowb_set_pending(); \ |
---|
145 | 118 | } |
---|
146 | | -#endif |
---|
147 | 119 | |
---|
148 | 120 | #define DEF_MMIO_IN_D(name, size, insn) \ |
---|
149 | 121 | static inline u##size name(const volatile u##size __iomem *addr) \ |
---|
.. | .. |
---|
159 | 131 | { \ |
---|
160 | 132 | __asm__ __volatile__("sync;"#insn"%U0%X0 %1,%0" \ |
---|
161 | 133 | : "=m" (*addr) : "r" (val) : "memory"); \ |
---|
162 | | - IO_SET_SYNC_FLAG(); \ |
---|
| 134 | + mmiowb_set_pending(); \ |
---|
163 | 135 | } |
---|
164 | 136 | |
---|
165 | 137 | DEF_MMIO_IN_D(in_8, 8, lbz); |
---|
.. | .. |
---|
372 | 344 | */ |
---|
373 | 345 | static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr) |
---|
374 | 346 | { |
---|
375 | | - __asm__ __volatile__("stbcix %0,0,%1" |
---|
| 347 | + __asm__ __volatile__(".machine push; \ |
---|
| 348 | + .machine power6; \ |
---|
| 349 | + stbcix %0,0,%1; \ |
---|
| 350 | + .machine pop;" |
---|
376 | 351 | : : "r" (val), "r" (paddr) : "memory"); |
---|
377 | 352 | } |
---|
378 | 353 | |
---|
379 | 354 | static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr) |
---|
380 | 355 | { |
---|
381 | | - __asm__ __volatile__("sthcix %0,0,%1" |
---|
| 356 | + __asm__ __volatile__(".machine push; \ |
---|
| 357 | + .machine power6; \ |
---|
| 358 | + sthcix %0,0,%1; \ |
---|
| 359 | + .machine pop;" |
---|
382 | 360 | : : "r" (val), "r" (paddr) : "memory"); |
---|
383 | 361 | } |
---|
384 | 362 | |
---|
385 | 363 | static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr) |
---|
386 | 364 | { |
---|
387 | | - __asm__ __volatile__("stwcix %0,0,%1" |
---|
| 365 | + __asm__ __volatile__(".machine push; \ |
---|
| 366 | + .machine power6; \ |
---|
| 367 | + stwcix %0,0,%1; \ |
---|
| 368 | + .machine pop;" |
---|
388 | 369 | : : "r" (val), "r" (paddr) : "memory"); |
---|
389 | 370 | } |
---|
390 | 371 | |
---|
391 | 372 | static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr) |
---|
392 | 373 | { |
---|
393 | | - __asm__ __volatile__("stdcix %0,0,%1" |
---|
| 374 | + __asm__ __volatile__(".machine push; \ |
---|
| 375 | + .machine power6; \ |
---|
| 376 | + stdcix %0,0,%1; \ |
---|
| 377 | + .machine pop;" |
---|
394 | 378 | : : "r" (val), "r" (paddr) : "memory"); |
---|
395 | 379 | } |
---|
396 | 380 | |
---|
.. | .. |
---|
402 | 386 | static inline u8 __raw_rm_readb(volatile void __iomem *paddr) |
---|
403 | 387 | { |
---|
404 | 388 | u8 ret; |
---|
405 | | - __asm__ __volatile__("lbzcix %0,0, %1" |
---|
| 389 | + __asm__ __volatile__(".machine push; \ |
---|
| 390 | + .machine power6; \ |
---|
| 391 | + lbzcix %0,0, %1; \ |
---|
| 392 | + .machine pop;" |
---|
406 | 393 | : "=r" (ret) : "r" (paddr) : "memory"); |
---|
407 | 394 | return ret; |
---|
408 | 395 | } |
---|
.. | .. |
---|
410 | 397 | static inline u16 __raw_rm_readw(volatile void __iomem *paddr) |
---|
411 | 398 | { |
---|
412 | 399 | u16 ret; |
---|
413 | | - __asm__ __volatile__("lhzcix %0,0, %1" |
---|
| 400 | + __asm__ __volatile__(".machine push; \ |
---|
| 401 | + .machine power6; \ |
---|
| 402 | + lhzcix %0,0, %1; \ |
---|
| 403 | + .machine pop;" |
---|
414 | 404 | : "=r" (ret) : "r" (paddr) : "memory"); |
---|
415 | 405 | return ret; |
---|
416 | 406 | } |
---|
.. | .. |
---|
418 | 408 | static inline u32 __raw_rm_readl(volatile void __iomem *paddr) |
---|
419 | 409 | { |
---|
420 | 410 | u32 ret; |
---|
421 | | - __asm__ __volatile__("lwzcix %0,0, %1" |
---|
| 411 | + __asm__ __volatile__(".machine push; \ |
---|
| 412 | + .machine power6; \ |
---|
| 413 | + lwzcix %0,0, %1; \ |
---|
| 414 | + .machine pop;" |
---|
422 | 415 | : "=r" (ret) : "r" (paddr) : "memory"); |
---|
423 | 416 | return ret; |
---|
424 | 417 | } |
---|
.. | .. |
---|
426 | 419 | static inline u64 __raw_rm_readq(volatile void __iomem *paddr) |
---|
427 | 420 | { |
---|
428 | 421 | u64 ret; |
---|
429 | | - __asm__ __volatile__("ldcix %0,0, %1" |
---|
| 422 | + __asm__ __volatile__(".machine push; \ |
---|
| 423 | + .machine power6; \ |
---|
| 424 | + ldcix %0,0, %1; \ |
---|
| 425 | + .machine pop;" |
---|
430 | 426 | : "=r" (ret) : "r" (paddr) : "memory"); |
---|
431 | 427 | return ret; |
---|
432 | 428 | } |
---|
.. | .. |
---|
667 | 663 | |
---|
668 | 664 | #include <asm-generic/iomap.h> |
---|
669 | 665 | |
---|
670 | | -#ifdef CONFIG_PPC32 |
---|
671 | | -#define mmiowb() |
---|
672 | | -#else |
---|
673 | | -/* |
---|
674 | | - * Enforce synchronisation of stores vs. spin_unlock |
---|
675 | | - * (this does it explicitly, though our implementation of spin_unlock |
---|
676 | | - * does it implicitely too) |
---|
677 | | - */ |
---|
678 | | -static inline void mmiowb(void) |
---|
679 | | -{ |
---|
680 | | - unsigned long tmp; |
---|
681 | | - |
---|
682 | | - __asm__ __volatile__("sync; li %0,0; stb %0,%1(13)" |
---|
683 | | - : "=&r" (tmp) : "i" (offsetof(struct paca_struct, io_sync)) |
---|
684 | | - : "memory"); |
---|
685 | | -} |
---|
686 | | -#endif /* !CONFIG_PPC32 */ |
---|
687 | | - |
---|
688 | 666 | static inline void iosync(void) |
---|
689 | 667 | { |
---|
690 | 668 | __asm__ __volatile__ ("sync" : : : "memory"); |
---|
.. | .. |
---|
736 | 714 | * * ioremap_prot allows to specify the page flags as an argument and can |
---|
737 | 715 | * also be hooked by the platform via ppc_md. |
---|
738 | 716 | * |
---|
739 | | - * * ioremap_nocache is identical to ioremap |
---|
740 | | - * |
---|
741 | 717 | * * ioremap_wc enables write combining |
---|
| 718 | + * |
---|
| 719 | + * * ioremap_wt enables write through |
---|
| 720 | + * |
---|
| 721 | + * * ioremap_coherent maps coherent cached memory |
---|
742 | 722 | * |
---|
743 | 723 | * * iounmap undoes such a mapping and can be hooked |
---|
744 | 724 | * |
---|
745 | | - * * __ioremap_at (and the pending __iounmap_at) are low level functions to |
---|
746 | | - * create hand-made mappings for use only by the PCI code and cannot |
---|
747 | | - * currently be hooked. Must be page aligned. |
---|
748 | | - * |
---|
749 | | - * * __ioremap is the low level implementation used by ioremap and |
---|
750 | | - * ioremap_prot and cannot be hooked (but can be used by a hook on one |
---|
751 | | - * of the previous ones) |
---|
752 | | - * |
---|
753 | 725 | * * __ioremap_caller is the same as above but takes an explicit caller |
---|
754 | 726 | * reference rather than using __builtin_return_address(0) |
---|
755 | | - * |
---|
756 | | - * * __iounmap, is the low level implementation used by iounmap and cannot |
---|
757 | | - * be hooked (but can be used by a hook on iounmap) |
---|
758 | 727 | * |
---|
759 | 728 | */ |
---|
760 | 729 | extern void __iomem *ioremap(phys_addr_t address, unsigned long size); |
---|
761 | 730 | extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size, |
---|
762 | 731 | unsigned long flags); |
---|
763 | 732 | extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size); |
---|
764 | | -#define ioremap_nocache(addr, size) ioremap((addr), (size)) |
---|
| 733 | +void __iomem *ioremap_wt(phys_addr_t address, unsigned long size); |
---|
| 734 | +void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size); |
---|
765 | 735 | #define ioremap_uc(addr, size) ioremap((addr), (size)) |
---|
766 | 736 | #define ioremap_cache(addr, size) \ |
---|
767 | 737 | ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) |
---|
768 | 738 | |
---|
769 | 739 | extern void iounmap(volatile void __iomem *addr); |
---|
770 | 740 | |
---|
771 | | -extern void __iomem *__ioremap(phys_addr_t, unsigned long size, |
---|
772 | | - unsigned long flags); |
---|
| 741 | +void __iomem *ioremap_phb(phys_addr_t paddr, unsigned long size); |
---|
| 742 | + |
---|
| 743 | +int early_ioremap_range(unsigned long ea, phys_addr_t pa, |
---|
| 744 | + unsigned long size, pgprot_t prot); |
---|
| 745 | +void __iomem *do_ioremap(phys_addr_t pa, phys_addr_t offset, unsigned long size, |
---|
| 746 | + pgprot_t prot, void *caller); |
---|
| 747 | + |
---|
773 | 748 | extern void __iomem *__ioremap_caller(phys_addr_t, unsigned long size, |
---|
774 | | - unsigned long flags, void *caller); |
---|
775 | | - |
---|
776 | | -extern void __iounmap(volatile void __iomem *addr); |
---|
777 | | - |
---|
778 | | -extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea, |
---|
779 | | - unsigned long size, unsigned long flags); |
---|
780 | | -extern void __iounmap_at(void *ea, unsigned long size); |
---|
| 749 | + pgprot_t prot, void *caller); |
---|
781 | 750 | |
---|
782 | 751 | /* |
---|
783 | 752 | * When CONFIG_PPC_INDIRECT_PIO is set, we use the generic iomap implementation |
---|
.. | .. |
---|
792 | 761 | |
---|
793 | 762 | #define mmio_read16be(addr) readw_be(addr) |
---|
794 | 763 | #define mmio_read32be(addr) readl_be(addr) |
---|
| 764 | +#define mmio_read64be(addr) readq_be(addr) |
---|
795 | 765 | #define mmio_write16be(val, addr) writew_be(val, addr) |
---|
796 | 766 | #define mmio_write32be(val, addr) writel_be(val, addr) |
---|
| 767 | +#define mmio_write64be(val, addr) writeq_be(val, addr) |
---|
797 | 768 | #define mmio_insb(addr, dst, count) readsb(addr, dst, count) |
---|
798 | 769 | #define mmio_insw(addr, dst, count) readsw(addr, dst, count) |
---|
799 | 770 | #define mmio_insl(addr, dst, count) readsl(addr, dst, count) |
---|
.. | .. |
---|
815 | 786 | */ |
---|
816 | 787 | static inline unsigned long virt_to_phys(volatile void * address) |
---|
817 | 788 | { |
---|
| 789 | + WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && !virt_addr_valid(address)); |
---|
| 790 | + |
---|
818 | 791 | return __pa((unsigned long)address); |
---|
819 | 792 | } |
---|
820 | 793 | |
---|
.. | .. |
---|
838 | 811 | /* |
---|
839 | 812 | * Change "struct page" to physical address. |
---|
840 | 813 | */ |
---|
841 | | -#define page_to_phys(page) ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT) |
---|
| 814 | +static inline phys_addr_t page_to_phys(struct page *page) |
---|
| 815 | +{ |
---|
| 816 | + unsigned long pfn = page_to_pfn(page); |
---|
| 817 | + |
---|
| 818 | + WARN_ON(IS_ENABLED(CONFIG_DEBUG_VIRTUAL) && !pfn_valid(pfn)); |
---|
| 819 | + |
---|
| 820 | + return PFN_PHYS(pfn); |
---|
| 821 | +} |
---|
842 | 822 | |
---|
843 | 823 | /* |
---|
844 | 824 | * 32 bits still uses virt_to_bus() for it's implementation of DMA |
---|