| .. | .. |
|---|
| 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 |
|---|