Patch "of: address: Fix address translation when address-size is greater than 2" has been added to the 6.5-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

    of: address: Fix address translation when address-size is greater than 2

to the 6.5-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:
     of-address-fix-address-translation-when-address-size.patch
and it can be found in the queue-6.5 subdirectory.

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



commit 8f137c97af4f73e8c26ab4a6ce57af18d2bb5095
Author: Herve Codina <herve.codina@xxxxxxxxxxx>
Date:   Tue Oct 17 13:02:16 2023 +0200

    of: address: Fix address translation when address-size is greater than 2
    
    [ Upstream commit 42604f8eb7ba04b589375049cc76282dad4677d2 ]
    
    With the recent addition of of_pci_prop_ranges() in commit 407d1a51921e
    ("PCI: Create device tree node for bridge"), the ranges property can
    have a 3 cells child address, a 3 cells parent address and a 2 cells
    child size.
    
    A range item property for a PCI device is filled as follow:
      <BAR_nbr> 0 0 <phys.hi> <phys.mid> <phys.low> <BAR_sizeh> <BAR_sizel>
      <-- Child --> <-- Parent (PCI definition) --> <- BAR size (64bit) -->
    
    This allow to translate BAR addresses from the DT. For instance:
    pci@0,0 {
      #address-cells = <0x03>;
      #size-cells = <0x02>;
      device_type = "pci";
      compatible = "pci11ab,100", "pciclass,060400", "pciclass,0604";
      ranges = <0x82000000 0x00 0xe8000000
                0x82000000 0x00 0xe8000000
                0x00 0x4400000>;
      ...
      dev@0,0 {
        #address-cells = <0x03>;
        #size-cells = <0x02>;
        compatible = "pci1055,9660", "pciclass,020000", "pciclass,0200";
        /* Translations for BAR0 to BAR5 */
        ranges = <0x00 0x00 0x00 0x82010000 0x00 0xe8000000 0x00 0x2000000
                  0x01 0x00 0x00 0x82010000 0x00 0xea000000 0x00 0x1000000
                  0x02 0x00 0x00 0x82010000 0x00 0xeb000000 0x00 0x800000
                  0x03 0x00 0x00 0x82010000 0x00 0xeb800000 0x00 0x800000
                  0x04 0x00 0x00 0x82010000 0x00 0xec000000 0x00 0x20000
                  0x05 0x00 0x00 0x82010000 0x00 0xec020000 0x00 0x2000>;
        ...
        pci-ep-bus@0 {
          #address-cells = <0x01>;
          #size-cells = <0x01>;
          compatible = "simple-bus";
          /* Translate 0xe2000000 to BAR0 and 0xe0000000 to BAR1 */
          ranges = <0xe2000000 0x00 0x00 0x00 0x2000000
                    0xe0000000 0x01 0x00 0x00 0x1000000>;
          ...
        };
      };
    };
    
    During the translation process, the "default-flags" map() function is
    used to select the matching item in the ranges table and determine the
    address offset from this matching item.
    This map() function simply calls of_read_number() and when address-size
    is greater than 2, the map() function skips the extra high address part
    (ie part over 64bit). This lead to a wrong matching item and a wrong
    offset computation.
    Also during the translation itself, the extra high part related to the
    parent address is not present in the translated address.
    
    Fix the "default-flags" map() and translate() in order to take into
    account the child extra high address part in map() and the parent extra
    high address part in translate() and so having a correct address
    translation for ranges patterns such as the one given in the example
    above.
    
    Signed-off-by: Herve Codina <herve.codina@xxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20231017110221.189299-2-herve.codina@xxxxxxxxxxx
    Signed-off-by: Rob Herring <robh@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/of/address.c b/drivers/of/address.c
index e692809ff8227..3219c51777507 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -100,6 +100,32 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
 	return IORESOURCE_MEM;
 }
 
+static u64 of_bus_default_flags_map(__be32 *addr, const __be32 *range, int na,
+				    int ns, int pna)
+{
+	u64 cp, s, da;
+
+	/* Check that flags match */
+	if (*addr != *range)
+		return OF_BAD_ADDR;
+
+	/* Read address values, skipping high cell */
+	cp = of_read_number(range + 1, na - 1);
+	s  = of_read_number(range + na + pna, ns);
+	da = of_read_number(addr + 1, na - 1);
+
+	pr_debug("default flags map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
+
+	if (da < cp || da >= (cp + s))
+		return OF_BAD_ADDR;
+	return da - cp;
+}
+
+static int of_bus_default_flags_translate(__be32 *addr, u64 offset, int na)
+{
+	/* Keep "flags" part (high cell) in translated address */
+	return of_bus_default_translate(addr + 1, offset, na - 1);
+}
 
 #ifdef CONFIG_PCI
 static unsigned int of_bus_pci_get_flags(const __be32 *addr)
@@ -374,8 +400,8 @@ static struct of_bus of_busses[] = {
 		.addresses = "reg",
 		.match = of_bus_default_flags_match,
 		.count_cells = of_bus_default_count_cells,
-		.map = of_bus_default_map,
-		.translate = of_bus_default_translate,
+		.map = of_bus_default_flags_map,
+		.translate = of_bus_default_flags_translate,
 		.has_flags = true,
 		.get_flags = of_bus_default_flags_get_flags,
 	},



[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