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

x86: remove 32-bit versions of readq()/writeq()

The presense of a writeq() implementation on 32-bit x86 that splits the
64-bit write into two 32-bit writes turns out to break the mpt2sas driver
(and in general is risky for drivers as was discussed in
<http://lkml.kernel.org/r/adaab6c1h7c.fsf@cisco.com>). To fix this,
revert 2c5643b1c5c7 ("x86: provide readq()/writeq() on 32-bit too") and
follow-on cleanups.

This unfortunately leads to pushing non-atomic definitions of readq() and
write() to various x86-only drivers that in the meantime started using the
definitions in the x86 version of <asm/io.h>. However as discussed
exhaustively, this is actually the right thing to do, because the right
way to split a 64-bit transaction is hardware dependent and therefore
belongs in the hardware driver (eg mpt2sas needs a spinlock to make sure
no other accesses occur in between the two halves of the access).

Build tested on 32- and 64-bit x86 allmodconfig.

Link: http://lkml.kernel.org/r/x86-32-writeq-is-broken@mdm.bga.com
Acked-by: Hitoshi Mitake <h.mitake@gmail.com>
Cc: Kashyap Desai <Kashyap.Desai@lsi.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Ravi Anand <ravi.anand@qlogic.com>
Cc: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Cc: Matthew Garrett <mjg@redhat.com>
Cc: Jason Uhlenkott <juhlenko@akamai.com>
Acked-by: James Bottomley <James.Bottomley@parallels.com>
Acked-by: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Roland Dreier and committed by
Linus Torvalds
dbee8a0a 818b667b

+74 -24
-2
arch/x86/Kconfig
··· 17 17 config X86 18 18 def_bool y 19 19 select HAVE_AOUT if X86_32 20 - select HAVE_READQ 21 - select HAVE_WRITEQ 22 20 select HAVE_UNSTABLE_SCHED_CLOCK 23 21 select HAVE_IDE 24 22 select HAVE_OPROFILE
+2 -22
arch/x86/include/asm/io.h
··· 38 38 39 39 #include <linux/string.h> 40 40 #include <linux/compiler.h> 41 - #include <asm-generic/int-ll64.h> 42 41 #include <asm/page.h> 43 42 44 43 #include <xen/xen.h> ··· 86 87 build_mmio_read(readq, "q", unsigned long, "=r", :"memory") 87 88 build_mmio_write(writeq, "q", unsigned long, "r", :"memory") 88 89 89 - #else 90 - 91 - static inline __u64 readq(const volatile void __iomem *addr) 92 - { 93 - const volatile u32 __iomem *p = addr; 94 - u32 low, high; 95 - 96 - low = readl(p); 97 - high = readl(p + 1); 98 - 99 - return low + ((u64)high << 32); 100 - } 101 - 102 - static inline void writeq(__u64 val, volatile void __iomem *addr) 103 - { 104 - writel(val, addr); 105 - writel(val >> 32, addr+4); 106 - } 107 - 108 - #endif 109 - 110 90 #define readq_relaxed(a) readq(a) 111 91 112 92 #define __raw_readq(a) readq(a) ··· 94 116 /* Let people know that we have them */ 95 117 #define readq readq 96 118 #define writeq writeq 119 + 120 + #endif 97 121 98 122 /** 99 123 * virt_to_phys - map virtual addresses to physical
+8
drivers/acpi/apei/einj.c
··· 101 101 102 102 static struct einj_parameter *einj_param; 103 103 104 + #ifndef writeq 105 + static inline void writeq(__u64 val, volatile void __iomem *addr) 106 + { 107 + writel(val, addr); 108 + writel(val >> 32, addr+4); 109 + } 110 + #endif 111 + 104 112 static void einj_exec_ctx_init(struct apei_exec_context *ctx) 105 113 { 106 114 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
+4
drivers/acpi/atomicio.c
··· 280 280 case 32: 281 281 *val = readl(addr); 282 282 break; 283 + #ifdef readq 283 284 case 64: 284 285 *val = readq(addr); 285 286 break; 287 + #endif 286 288 default: 287 289 return -EINVAL; 288 290 } ··· 309 307 case 32: 310 308 writel(val, addr); 311 309 break; 310 + #ifdef writeq 312 311 case 64: 313 312 writeq(val, addr); 314 313 break; 314 + #endif 315 315 default: 316 316 return -EINVAL; 317 317 }
+13
drivers/edac/i3200_edac.c
··· 101 101 102 102 static int nr_channels; 103 103 104 + #ifndef readq 105 + static inline __u64 readq(const volatile void __iomem *addr) 106 + { 107 + const volatile u32 __iomem *p = addr; 108 + u32 low, high; 109 + 110 + low = readl(p); 111 + high = readl(p + 1); 112 + 113 + return low + ((u64)high << 32); 114 + } 115 + #endif 116 + 104 117 static int how_many_channels(struct pci_dev *pdev) 105 118 { 106 119 unsigned char capid0_8b; /* 8th byte of CAPID0 */
+13
drivers/platform/x86/ibm_rtl.c
··· 81 81 static u8 rtl_cmd_type; 82 82 static u8 rtl_cmd_width; 83 83 84 + #ifndef readq 85 + static inline __u64 readq(const volatile void __iomem *addr) 86 + { 87 + const volatile u32 __iomem *p = addr; 88 + u32 low, high; 89 + 90 + low = readl(p); 91 + high = readl(p + 1); 92 + 93 + return low + ((u64)high << 32); 94 + } 95 + #endif 96 + 84 97 static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len) 85 98 { 86 99 if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
+13
drivers/platform/x86/intel_ips.c
··· 344 344 static bool 345 345 ips_gpu_turbo_enabled(struct ips_driver *ips); 346 346 347 + #ifndef readq 348 + static inline __u64 readq(const volatile void __iomem *addr) 349 + { 350 + const volatile u32 __iomem *p = addr; 351 + u32 low, high; 352 + 353 + low = readl(p); 354 + high = readl(p + 1); 355 + 356 + return low + ((u64)high << 32); 357 + } 358 + #endif 359 + 347 360 /** 348 361 * ips_cpu_busy - is CPU busy? 349 362 * @ips: IPS driver struct
+21
drivers/scsi/qla4xxx/ql4_nx.c
··· 655 655 return 0; 656 656 } 657 657 658 + #ifndef readq 659 + static inline __u64 readq(const volatile void __iomem *addr) 660 + { 661 + const volatile u32 __iomem *p = addr; 662 + u32 low, high; 663 + 664 + low = readl(p); 665 + high = readl(p + 1); 666 + 667 + return low + ((u64)high << 32); 668 + } 669 + #endif 670 + 671 + #ifndef writeq 672 + static inline void writeq(__u64 val, volatile void __iomem *addr) 673 + { 674 + writel(val, addr); 675 + writel(val >> 32, addr+4); 676 + } 677 + #endif 678 + 658 679 static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha, 659 680 u64 off, void *data, int size) 660 681 {