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

s390/pci: Implement ioremap_wc/prot() with MIO

With our current support for the new MIO PCI instructions, write
combining/write back MMIO memory can be obtained via the pci_iomap_wc()
and pci_iomap_wc_range() functions.
This is achieved by using the write back address for a specific bar
as provided in clp_store_query_pci_fn()

These functions are however not widely used and instead drivers often
rely on ioremap_wc() and ioremap_prot(), which on other platforms enable
write combining using a PTE flag set through the pgrprot value.

While we do not have a write combining flag in the low order flag bits
of the PTE like x86_64 does, with MIO support, there is a write back bit
in the physical address (bit 1 on z15) and thus also the PTE.
Which bit is used to toggle write back and whether it is available at
all, is however not fixed in the architecture. Instead we get this
information from the CLP Store Logical Processor Characteristics for PCI
command. When the write back bit is not provided we fall back to the
existing behavior.

Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>

authored by

Niklas Schnelle and committed by
Vasily Gorbik
b02002cc 4d4a3caa

+132 -5
+1 -1
Documentation/features/vm/ioremap_prot/arch-support.txt
··· 24 24 | parisc: | TODO | 25 25 | powerpc: | ok | 26 26 | riscv: | TODO | 27 - | s390: | TODO | 27 + | s390: | ok | 28 28 | sh: | ok | 29 29 | sparc: | TODO | 30 30 | um: | TODO |
+3
arch/s390/include/asm/clp.h
··· 5 5 /* CLP common request & response block size */ 6 6 #define CLP_BLK_SIZE PAGE_SIZE 7 7 8 + /* Call Logical Processor - Command Code */ 9 + #define CLP_SLPC 0x0001 10 + 8 11 #define CLP_LPS_BASE 0 9 12 #define CLP_LPS_PCI 2 10 13
+8
arch/s390/include/asm/io.h
··· 12 12 13 13 #include <linux/kernel.h> 14 14 #include <asm/page.h> 15 + #include <asm/pgtable.h> 15 16 #include <asm/pci_io.h> 16 17 17 18 #define xlate_dev_mem_ptr xlate_dev_mem_ptr ··· 27 26 28 27 #define IO_SPACE_LIMIT 0 29 28 29 + void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot); 30 30 void __iomem *ioremap(phys_addr_t addr, size_t size); 31 + void __iomem *ioremap_wc(phys_addr_t addr, size_t size); 32 + void __iomem *ioremap_wt(phys_addr_t addr, size_t size); 31 33 void iounmap(volatile void __iomem *addr); 32 34 33 35 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) ··· 55 51 #define pci_iounmap pci_iounmap 56 52 #define pci_iomap_wc pci_iomap_wc 57 53 #define pci_iomap_wc_range pci_iomap_wc_range 54 + 55 + #define ioremap ioremap 56 + #define ioremap_wt ioremap_wt 57 + #define ioremap_wc ioremap_wc 58 58 59 59 #define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count) 60 60 #define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
+1
arch/s390/include/asm/pci.h
··· 208 208 void zpci_remove_reserved_devices(void); 209 209 210 210 /* CLP */ 211 + int clp_setup_writeback_mio(void); 211 212 int clp_scan_pci_devices(void); 212 213 int clp_rescan_pci_devices(void); 213 214 int clp_rescan_pci_devices_simple(u32 *fid);
+19
arch/s390/include/asm/pci_clp.h
··· 7 7 /* 8 8 * Call Logical Processor - Command Codes 9 9 */ 10 + #define CLP_SLPC 0x0001 10 11 #define CLP_LIST_PCI 0x0002 11 12 #define CLP_QUERY_PCI_FN 0x0003 12 13 #define CLP_QUERY_PCI_FNGRP 0x0004 ··· 51 50 #define CLP_PFIP_NR_SEGMENTS 4 52 51 53 52 extern bool zpci_unique_uid; 53 + 54 + struct clp_rsp_slpc_pci { 55 + struct clp_rsp_hdr hdr; 56 + u32 reserved2[4]; 57 + u32 lpif[8]; 58 + u32 reserved3[4]; 59 + u32 vwb : 1; 60 + u32 : 1; 61 + u32 mio_wb : 6; 62 + u32 : 24; 63 + u32 reserved5[3]; 64 + u32 lpic[8]; 65 + } __packed; 54 66 55 67 /* List PCI functions request */ 56 68 struct clp_req_list_pci { ··· 186 172 } __packed; 187 173 188 174 /* Combined request/response block structures used by clp insn */ 175 + struct clp_req_rsp_slpc_pci { 176 + struct clp_req_slpc request; 177 + struct clp_rsp_slpc_pci response; 178 + } __packed; 179 + 189 180 struct clp_req_rsp_list_pci { 190 181 struct clp_req_list_pci request; 191 182 struct clp_rsp_list_pci response;
+8 -1
arch/s390/include/asm/pgtable.h
··· 1186 1186 void gmap_pmdp_idte_local(struct mm_struct *mm, unsigned long vmaddr); 1187 1187 void gmap_pmdp_idte_global(struct mm_struct *mm, unsigned long vmaddr); 1188 1188 1189 + #define pgprot_writecombine pgprot_writecombine 1190 + pgprot_t pgprot_writecombine(pgprot_t prot); 1191 + 1192 + #define pgprot_writethrough pgprot_writethrough 1193 + pgprot_t pgprot_writethrough(pgprot_t prot); 1194 + 1189 1195 /* 1190 1196 * Certain architectures need to do special things when PTEs 1191 1197 * within a page table are directly modified. Thus, the following ··· 1215 1209 static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) 1216 1210 { 1217 1211 pte_t __pte; 1218 - pte_val(__pte) = physpage + pgprot_val(pgprot); 1212 + 1213 + pte_val(__pte) = physpage | pgprot_val(pgprot); 1219 1214 if (!MACHINE_HAS_NX) 1220 1215 pte_val(__pte) &= ~_PAGE_NOEXEC; 1221 1216 return pte_mkyoung(__pte);
+3
arch/s390/include/asm/setup.h
··· 94 94 extern unsigned long max_physmem_end; 95 95 extern unsigned long __swsusp_reset_dma; 96 96 97 + /* The Write Back bit position in the physaddr is given by the SLPC PCI */ 98 + extern unsigned long mio_wb_bit_mask; 99 + 97 100 #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) 98 101 #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) 99 102 #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR)
+6
arch/s390/kernel/setup.c
··· 128 128 EXPORT_SYMBOL(lowcore_ptr); 129 129 130 130 /* 131 + * The Write Back bit position in the physaddr is given by the SLPC PCI. 132 + * Leaving the mask zero always uses write through which is safe 133 + */ 134 + unsigned long mio_wb_bit_mask __ro_after_init; 135 + 136 + /* 131 137 * This is set up by the setup-routine at boot-time 132 138 * for S390 need to find out, what we have to setup 133 139 * using address 0x10400 ...
+20
arch/s390/mm/pgtable.c
··· 24 24 #include <asm/mmu_context.h> 25 25 #include <asm/page-states.h> 26 26 27 + pgprot_t pgprot_writecombine(pgprot_t prot) 28 + { 29 + /* 30 + * mio_wb_bit_mask may be set on a different CPU, but it is only set 31 + * once at init and only read afterwards. 32 + */ 33 + return __pgprot(pgprot_val(prot) | mio_wb_bit_mask); 34 + } 35 + EXPORT_SYMBOL_GPL(pgprot_writecombine); 36 + 37 + pgprot_t pgprot_writethrough(pgprot_t prot) 38 + { 39 + /* 40 + * mio_wb_bit_mask may be set on a different CPU, but it is only set 41 + * once at init and only read afterwards. 42 + */ 43 + return __pgprot(pgprot_val(prot) & ~mio_wb_bit_mask); 44 + } 45 + EXPORT_SYMBOL_GPL(pgprot_writethrough); 46 + 27 47 static inline void ptep_ipte_local(struct mm_struct *mm, unsigned long addr, 28 48 pte_t *ptep, int nodat) 29 49 {
+28 -2
arch/s390/pci/pci.c
··· 226 226 zpci_memcpy_toio(to, from, count); 227 227 } 228 228 229 - void __iomem *ioremap(phys_addr_t addr, size_t size) 229 + static void __iomem *__ioremap(phys_addr_t addr, size_t size, pgprot_t prot) 230 230 { 231 231 unsigned long offset, vaddr; 232 232 struct vm_struct *area; ··· 247 247 return NULL; 248 248 249 249 vaddr = (unsigned long) area->addr; 250 - if (ioremap_page_range(vaddr, vaddr + size, addr, PAGE_KERNEL)) { 250 + if (ioremap_page_range(vaddr, vaddr + size, addr, prot)) { 251 251 free_vm_area(area); 252 252 return NULL; 253 253 } 254 254 return (void __iomem *) ((unsigned long) area->addr + offset); 255 255 } 256 + 257 + void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot) 258 + { 259 + return __ioremap(addr, size, __pgprot(prot)); 260 + } 261 + EXPORT_SYMBOL(ioremap_prot); 262 + 263 + void __iomem *ioremap(phys_addr_t addr, size_t size) 264 + { 265 + return __ioremap(addr, size, PAGE_KERNEL); 266 + } 256 267 EXPORT_SYMBOL(ioremap); 268 + 269 + void __iomem *ioremap_wc(phys_addr_t addr, size_t size) 270 + { 271 + return __ioremap(addr, size, pgprot_writecombine(PAGE_KERNEL)); 272 + } 273 + EXPORT_SYMBOL(ioremap_wc); 274 + 275 + void __iomem *ioremap_wt(phys_addr_t addr, size_t size) 276 + { 277 + return __ioremap(addr, size, pgprot_writethrough(PAGE_KERNEL)); 278 + } 279 + EXPORT_SYMBOL(ioremap_wt); 257 280 258 281 void iounmap(volatile void __iomem *addr) 259 282 { ··· 806 783 sizeof(*zpci_iomap_bitmap), GFP_KERNEL); 807 784 if (!zpci_iomap_bitmap) 808 785 goto error_iomap_bitmap; 786 + 787 + if (static_branch_likely(&have_mio)) 788 + clp_setup_writeback_mio(); 809 789 810 790 return 0; 811 791 error_iomap_bitmap:
+35 -1
arch/s390/pci/pci_clp.c
··· 292 292 return rc; 293 293 } 294 294 295 + int clp_setup_writeback_mio(void) 296 + { 297 + struct clp_req_rsp_slpc_pci *rrb; 298 + u8 wb_bit_pos; 299 + int rc; 300 + 301 + rrb = clp_alloc_block(GFP_KERNEL); 302 + if (!rrb) 303 + return -ENOMEM; 304 + 305 + memset(rrb, 0, sizeof(*rrb)); 306 + rrb->request.hdr.len = sizeof(rrb->request); 307 + rrb->request.hdr.cmd = CLP_SLPC; 308 + rrb->response.hdr.len = sizeof(rrb->response); 309 + 310 + rc = clp_req(rrb, CLP_LPS_PCI); 311 + if (!rc && rrb->response.hdr.rsp == CLP_RC_OK) { 312 + if (rrb->response.vwb) { 313 + wb_bit_pos = rrb->response.mio_wb; 314 + set_bit_inv(wb_bit_pos, &mio_wb_bit_mask); 315 + zpci_dbg(3, "wb bit: %d\n", wb_bit_pos); 316 + } else { 317 + zpci_dbg(3, "wb bit: n.a.\n"); 318 + } 319 + 320 + } else { 321 + zpci_err("SLPC PCI:\n"); 322 + zpci_err_clp(rrb->response.hdr.rsp, rc); 323 + rc = -EIO; 324 + } 325 + clp_free_block(rrb); 326 + return rc; 327 + } 328 + 295 329 int clp_enable_fh(struct zpci_dev *zdev, u8 nr_dma_as) 296 330 { 297 331 int rc; ··· 529 495 } 530 496 } 531 497 532 - static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc *lpcb) 498 + static int clp_pci_slpc(struct clp_req *req, struct clp_req_rsp_slpc_pci *lpcb) 533 499 { 534 500 unsigned long limit = PAGE_SIZE - sizeof(lpcb->request); 535 501