Skip to content

Commit

Permalink
PCI: dwc: Add iATU regions size detection procedure
Browse files Browse the repository at this point in the history
The DWC PCIe RC/EP/DM IP core configuration parameters determine the number
of inbound and outbound iATU windows, alignment requirements (which is also
the minimum window size), minimum and maximum sizes.  If internal ATU is
enabled, the former settings are determined by CX_ATU_MIN_REGION_SIZE; the
latter are determined by CX_ATU_MAX_REGION_SIZE.

Determine the required alignment and maximum size supported by the
controller and log it to help verify whether the requested inbound or
outbound memory mappings can be fully created.

Note 1. The extended iATU regions have been supported since DWC PCIe
v4.60a. There is no need in testing the upper limit register availability
for the older cores.

Note 2. The regions alignment is determined with using the fls() method
since the lower four bits of the ATU Limit register can be occupied with
the Circular Buffer Increment setting, which can be initialized with zeros.

Link: https://lore.kernel.org/r/20220624143947.8991-13-Sergey.Semin@baikalelectronics.ru
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
  • Loading branch information
Serge Semin authored and Bjorn Helgaas committed Aug 1, 2022
1 parent 5a163f5 commit 89473aa
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 4 deletions.
33 changes: 29 additions & 4 deletions drivers/pci/controller/dwc/pcie-designware.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
* Author: Jingoo Han <jg1.han@samsung.com>
*/

#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/sizes.h>
#include <linux/types.h>

#include "../../pci.h"
Expand Down Expand Up @@ -522,7 +524,8 @@ static bool dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
{
int max_region, ob, ib;
u32 val;
u32 val, min, dir;
u64 max;

if (pci->iatu_unroll_enabled) {
max_region = min((int)pci->atu_size / 512, 256);
Expand All @@ -545,8 +548,29 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci)
break;
}

pci->num_ib_windows = ib;
if (ob) {
dir = PCIE_ATU_REGION_DIR_OB;
} else if (ib) {
dir = PCIE_ATU_REGION_DIR_IB;
} else {
dev_err(pci->dev, "No iATU regions found\n");
return;
}

dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_LIMIT, 0x0);
min = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_LIMIT);

if (dw_pcie_ver_is_ge(pci, 460A)) {
dw_pcie_writel_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT, 0xFFFFFFFF);
max = dw_pcie_readl_atu(pci, dir, 0, PCIE_ATU_UPPER_LIMIT);
} else {
max = 0;
}

pci->num_ob_windows = ob;
pci->num_ib_windows = ib;
pci->region_align = 1 << fls(min);
pci->region_limit = (max << 32) | (SZ_4G - 1);
}

void dw_pcie_iatu_detect(struct dw_pcie *pci)
Expand Down Expand Up @@ -579,8 +603,9 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
dev_info(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
"enabled" : "disabled");

dev_info(pci->dev, "Detected iATU regions: %u outbound, %u inbound\n",
pci->num_ob_windows, pci->num_ib_windows);
dev_info(pci->dev, "iATU regions: %u ob, %u ib, align %uK, limit %lluG\n",
pci->num_ob_windows, pci->num_ib_windows,
pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
}

void dw_pcie_setup(struct dw_pcie *pci)
Expand Down
2 changes: 2 additions & 0 deletions drivers/pci/controller/dwc/pcie-designware.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ struct dw_pcie {
size_t atu_size;
u32 num_ib_windows;
u32 num_ob_windows;
u32 region_align;
u64 region_limit;
struct dw_pcie_rp pp;
struct dw_pcie_ep ep;
const struct dw_pcie_ops *ops;
Expand Down

0 comments on commit 89473aa

Please sign in to comment.