Patch "s390/pci: fix max size calculation in zpci_memcpy_toio()" has been added to the 5.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    s390/pci: fix max size calculation in zpci_memcpy_toio()

to the 5.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     s390-pci-fix-max-size-calculation-in-zpci_memcpy_toi.patch
and it can be found in the queue-5.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 750289f0827c8cd33fe34b7deaff74b59cdfb477
Author: Niklas Schnelle <schnelle@xxxxxxxxxxxxx>
Date:   Tue Nov 28 16:22:49 2023 +0100

    s390/pci: fix max size calculation in zpci_memcpy_toio()
    
    [ Upstream commit 80df7d6af7f6d229b34cf237b2cc9024c07111cd ]
    
    The zpci_get_max_write_size() helper is used to determine the maximum
    size a PCI store or load can use at a given __iomem address.
    
    For the PCI block store the following restrictions apply:
    
    1. The dst + len must not cross a 4K boundary in the (pseudo-)MMIO space
    2. len must not exceed ZPCI_MAX_WRITE_SIZE
    3. len must be a multiple of 8 bytes
    4. The src address must be double word (8 byte) aligned
    5. The dst address must be double word (8 byte) aligned
    
    Otherwise only a normal PCI store which takes its src value from
    a register can be used. For these PCI store restriction 1 still applies.
    Similarly 1 also applies to PCI loads.
    
    It turns out zpci_max_write_size() instead implements stricter
    conditions which prevents PCI block stores from being used where they
    can and should be used. In particular instead of conditions 4 and 5 it
    wrongly enforces both dst and src to be size aligned. This indirectly
    covers condition 1 but also prevents many legal PCI block stores.
    
    On top of the functional shortcomings the zpci_get_max_write_size() is
    misnamed as it is used for both read and write size calculations. Rename
    it to zpci_get_max_io_size() and implement the listed conditions
    explicitly.
    
    Reviewed-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx>
    Fixes: cd24834130ac ("s390/pci: base support")
    Signed-off-by: Niklas Schnelle <schnelle@xxxxxxxxxxxxx>
    [agordeev@xxxxxxxxxxxxx replaced spaces with tabs]
    Signed-off-by: Alexander Gordeev <agordeev@xxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h
index 287bb88f7698..2686bee800e3 100644
--- a/arch/s390/include/asm/pci_io.h
+++ b/arch/s390/include/asm/pci_io.h
@@ -11,6 +11,8 @@
 /* I/O size constraints */
 #define ZPCI_MAX_READ_SIZE	8
 #define ZPCI_MAX_WRITE_SIZE	128
+#define ZPCI_BOUNDARY_SIZE	(1 << 12)
+#define ZPCI_BOUNDARY_MASK	(ZPCI_BOUNDARY_SIZE - 1)
 
 /* I/O Map */
 #define ZPCI_IOMAP_SHIFT		48
@@ -125,16 +127,18 @@ static inline int zpci_read_single(void *dst, const volatile void __iomem *src,
 int zpci_write_block(volatile void __iomem *dst, const void *src,
 		     unsigned long len);
 
-static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
+static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max)
 {
-	int count = len > max ? max : len, size = 1;
+	int offset = dst & ZPCI_BOUNDARY_MASK;
+	int size;
 
-	while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
-		dst = dst >> 1;
-		src = src >> 1;
-		size = size << 1;
-	}
-	return size;
+	size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max);
+	if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8))
+		return size;
+
+	if (size >= 8)
+		return 8;
+	return rounddown_pow_of_two(size);
 }
 
 static inline int zpci_memcpy_fromio(void *dst,
@@ -144,9 +148,9 @@ static inline int zpci_memcpy_fromio(void *dst,
 	int size, rc = 0;
 
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) src,
-					       (u64) dst, n,
-					       ZPCI_MAX_READ_SIZE);
+		size = zpci_get_max_io_size((u64 __force) src,
+					    (u64) dst, n,
+					    ZPCI_MAX_READ_SIZE);
 		rc = zpci_read_single(dst, src, size);
 		if (rc)
 			break;
@@ -166,9 +170,9 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst,
 		return -EINVAL;
 
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) dst,
-					       (u64) src, n,
-					       ZPCI_MAX_WRITE_SIZE);
+		size = zpci_get_max_io_size((u64 __force) dst,
+					    (u64) src, n,
+					    ZPCI_MAX_WRITE_SIZE);
 		if (size > 8) /* main path */
 			rc = zpci_write_block(dst, src, size);
 		else
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c
index a4d5048b7eee..675e6cb50584 100644
--- a/arch/s390/pci/pci_mmio.c
+++ b/arch/s390/pci/pci_mmio.c
@@ -100,9 +100,9 @@ static inline int __memcpy_toio_inuser(void __iomem *dst,
 
 	old_fs = enable_sacf_uaccess();
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) dst,
-					       (u64 __force) src, n,
-					       ZPCI_MAX_WRITE_SIZE);
+		size = zpci_get_max_io_size((u64 __force) dst,
+					    (u64 __force) src, n,
+					    ZPCI_MAX_WRITE_SIZE);
 		if (size > 8) /* main path */
 			rc = __pcistb_mio_inuser(dst, src, size, &status);
 		else
@@ -250,9 +250,9 @@ static inline int __memcpy_fromio_inuser(void __user *dst,
 
 	old_fs = enable_sacf_uaccess();
 	while (n > 0) {
-		size = zpci_get_max_write_size((u64 __force) src,
-					       (u64 __force) dst, n,
-					       ZPCI_MAX_READ_SIZE);
+		size = zpci_get_max_io_size((u64 __force) src,
+					    (u64 __force) dst, n,
+					    ZPCI_MAX_READ_SIZE);
 		rc = __pcilg_mio_inuser(dst, src, size, &status);
 		if (rc)
 			break;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux