Patch "PCI: dwc: Fix index 0 incorrectly being interpreted as a free ATU slot" has been added to the 6.1-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

    PCI: dwc: Fix index 0 incorrectly being interpreted as a free ATU slot

to the 6.1-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:
     pci-dwc-fix-index-0-incorrectly-being-interpreted-as.patch
and it can be found in the queue-6.1 subdirectory.

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



commit c485b5ba027614cac226dcbfc184b7f10060bd97
Author: Frank Li <Frank.Li@xxxxxxx>
Date:   Fri Apr 12 12:08:41 2024 -0400

    PCI: dwc: Fix index 0 incorrectly being interpreted as a free ATU slot
    
    [ Upstream commit c2a57ee0f2f1ad8c970ff58b78a43e85abbdeb7f ]
    
    When PERST# assert and deassert happens on the PERST# supported platforms,
    both iATU0 and iATU6 will map inbound window to BAR0. DMA will access the
    area that was previously allocated (iATU0) for BAR0, instead of the new
    area (iATU6) for BAR0.
    
    Right now, this isn't an issue because both iATU0 and iATU6 should
    translate inbound accesses to BAR0 to the same allocated memory area.
    However, having two separate inbound mappings for the same BAR is a
    disaster waiting to happen.
    
    The mappings between PCI BAR and iATU inbound window are maintained in the
    dw_pcie_ep::bar_to_atu[] array. While allocating a new inbound iATU map for
    a BAR, dw_pcie_ep_inbound_atu() API checks for the availability of the
    existing mapping in the array and if it is not found (i.e., value in the
    array indexed by the BAR is found to be 0), it allocates a new map value
    using find_first_zero_bit().
    
    The issue is the existing logic failed to consider the fact that the map
    value '0' is a valid value for BAR0, so find_first_zero_bit() will return
    '0' as the map value for BAR0 (note that it returns the first zero bit
    position).
    
    Due to this, when PERST# assert + deassert happens on the PERST# supported
    platforms, the inbound window allocation restarts from BAR0 and the
    existing logic to find the BAR mapping will return '6' for BAR0 instead of
    '0' due to the fact that it considers '0' as an invalid map value.
    
    Fix this issue by always incrementing the map value before assigning to
    bar_to_atu[] array and then decrementing it while fetching. This will make
    sure that the map value '0' always represents the invalid mapping."
    
    Fixes: 4284c88fff0e ("PCI: designware-ep: Allow pci_epc_set_bar() update inbound map address")
    Closes: https://lore.kernel.org/linux-pci/ZXsRp+Lzg3x%2Fnhk3@x1-carbon/
    Link: https://lore.kernel.org/linux-pci/20240412160841.925927-1-Frank.Li@xxxxxxx
    Reported-by: Niklas Cassel <Niklas.Cassel@xxxxxxx>
    Tested-by: Niklas Cassel <niklas.cassel@xxxxxxx>
    Signed-off-by: Frank Li <Frank.Li@xxxxxxx>
    Signed-off-by: Krzysztof Wilczyński <kwilczynski@xxxxxxxxxx>
    Signed-off-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
    Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
    Reviewed-by: Niklas Cassel <niklas.cassel@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 506d6d061d4cd..449ad709495d3 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -165,7 +165,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
 	if (!ep->bar_to_atu[bar])
 		free_win = find_first_zero_bit(ep->ib_window_map, pci->num_ib_windows);
 	else
-		free_win = ep->bar_to_atu[bar];
+		free_win = ep->bar_to_atu[bar] - 1;
 
 	if (free_win >= pci->num_ib_windows) {
 		dev_err(pci->dev, "No free inbound window\n");
@@ -179,7 +179,11 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
 		return ret;
 	}
 
-	ep->bar_to_atu[bar] = free_win;
+	/*
+	 * Always increment free_win before assignment, since value 0 is used to identify
+	 * unallocated mapping.
+	 */
+	ep->bar_to_atu[bar] = free_win + 1;
 	set_bit(free_win, ep->ib_window_map);
 
 	return 0;
@@ -216,7 +220,10 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 	enum pci_barno bar = epf_bar->barno;
-	u32 atu_index = ep->bar_to_atu[bar];
+	u32 atu_index = ep->bar_to_atu[bar] - 1;
+
+	if (!ep->bar_to_atu[bar])
+		return;
 
 	__dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->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