[PATCH V4] PCI: Add MCFG quirks for Tegra194 host controllers

2021-04-16 Thread Vidya Sagar
The PCIe controller in Tegra194 SoC is not completely ECAM-compliant.
With the current hardware design limitations in place, ECAM can be enabled
only for one controller (C5 controller to be precise) with bus numbers
starting from 160 instead of 0. A different approach is taken to avoid this
abnormal way of enabling ECAM for just one controller but to enable
configuration space access for all the other controllers. In this approach,
ops are added through MCFG quirk mechanism which access the configuration
spaces by dynamically programming iATU (internal AddressTranslation Unit)
to generate respective configuration accesses just like the way it is
done in DesignWare core sub-system.
This issue is specific to Tegra194 and it would be fixed in the future
generations of Tegra SoCs.

Signed-off-by: Vidya Sagar 
---
V4:
* Addressed Bjorn's review comments
* Rebased changes on top of Lorenzo's pci/dwc branch

V3:
* Removed MCFG address hardcoding in pci_mcfg.c file
* Started using 'dbi_base' for accessing root port's own config space
* and using 'config_base' for accessing config space of downstream hierarchy

V2:
* Fixed build issues reported by kbuild test bot

 drivers/acpi/pci_mcfg.c|   7 ++
 drivers/pci/controller/dwc/Makefile|   2 +-
 drivers/pci/controller/dwc/pcie-tegra194.c | 103 +
 include/linux/pci-ecam.h   |   1 +
 4 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index 95f23acd5b80..53cab975f612 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = {
THUNDER_ECAM_QUIRK(2, 12),
THUNDER_ECAM_QUIRK(2, 13),
 
+   { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, _pcie_ops},
+   { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, _pcie_ops},
+
 #define XGENE_V1_ECAM_MCFG(rev, seg) \
{"APM   ", "XGENE   ", rev, seg, MCFG_BUS_ANY, \
_v1_pcie_ecam_ops }
diff --git a/drivers/pci/controller/dwc/Makefile 
b/drivers/pci/controller/dwc/Makefile
index 625f6aaeb5b8..2da826ef18ac 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
-obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
 obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
 
@@ -35,4 +34,5 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
 ifdef CONFIG_PCI
 obj-$(CONFIG_ARM64) += pcie-al.o
 obj-$(CONFIG_ARM64) += pcie-hisi.o
+obj-$(CONFIG_ARM64) += pcie-tegra194.o
 endif
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 6fa216e52d14..cb38e94a3033 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -22,6 +22,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -311,6 +313,104 @@ struct tegra_pcie_dw_of_data {
enum dw_pcie_device_mode mode;
 };
 
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
+struct tegra194_pcie_ecam  {
+   void __iomem *config_base;
+   void __iomem *iatu_base;
+   void __iomem *dbi_base;
+};
+
+static int tegra194_acpi_init(struct pci_config_window *cfg)
+{
+   struct device *dev = cfg->parent;
+   struct tegra194_pcie_ecam *pcie_ecam;
+
+   pcie_ecam = devm_kzalloc(dev, sizeof(*pcie_ecam), GFP_KERNEL);
+   if (!pcie_ecam)
+   return -ENOMEM;
+
+   pcie_ecam->config_base = cfg->win;
+   pcie_ecam->iatu_base = cfg->win + SZ_256K;
+   pcie_ecam->dbi_base = cfg->win + SZ_512K;
+   cfg->priv = pcie_ecam;
+
+   return 0;
+}
+
+static void atu_reg_write(struct tegra194_pcie_ecam *pcie_ecam, int index,
+ u32 val, u32 reg)
+{
+   u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
+
+   writel(val, pcie_ecam->iatu_base + offset + reg);
+}
+
+static void program_outbound_atu(struct tegra194_pcie_ecam *pcie_ecam,
+int index, int type, u64 cpu_addr,
+u64 pci_addr, u64 size)
+{
+   atu_reg_write(pcie_ecam, index, lower_32_bits(cpu_addr),
+ PCIE_ATU_LOWER_BASE);
+   atu_reg_write(pcie_ecam, index, upper_32_bits(cpu_addr),
+ PCIE_ATU_UPPER_BASE)

Re: [PATCH V3 2/2] PCI: Add MCFG quirks for Tegra194 host controllers

2021-04-16 Thread Vidya Sagar




On 3/6/2021 3:27 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


[+cc Krzysztof for .bus_shift below]

This is [2/2] but I don't see a [1/2].  Is there something missing?

On Sat, Jan 11, 2020 at 12:45:00AM +0530, Vidya Sagar wrote:

The PCIe controller in Tegra194 SoC is not completely ECAM-compliant.
With the current hardware design limitations in place, ECAM can be enabled
only for one controller (C5 controller to be precise) with bus numbers
starting from 160 instead of 0. A different approach is taken to avoid this
abnormal way of enabling ECAM for just one controller but to enable
configuration space access for all the other controllers. In this approach,
ops are added through MCFG quirk mechanism which access the configuration
spaces by dynamically programming iATU (internal AddressTranslation Unit)
to generate respective configuration accesses just like the way it is
done in DesignWare core sub-system.


Is this a published erratum in the device?  The purpose of specs is so
we can run existing code on new platforms without having to add quirks
like this, so I'm looking for some acknowledgement that this is an
issue that will be fixed in future designs.

Yes. This would be fixed in the following SoC.



Ideally this would be a URL to published errata, and we would include
the text or a synopsis here in the commit log.


Signed-off-by: Vidya Sagar 
Reported-by: kbuild test robot 


What is this "Reported-by" telling me?  Normally this would be a
person who could supply more information about a defect we're fixing
and might be able to test the fix.

I'll remove this.




---
V3:
* Removed MCFG address hardcoding in pci_mcfg.c file
* Started using 'dbi_base' for accessing root port's own config space
* and using 'config_base' for accessing config space of downstream hierarchy

V2:
* Fixed build issues reported by kbuild test bot


Ah, I see this is probably where the "Reported-by" came from.  To me,
it would make sense to add the tag if the commit *only* fixes the
build problem so it's obvious what the robot reported.

But here, the build fix got squashed in before merging, so it's more
like a general review comment and I think the robot's response on the
mailing list is probably enough.


  drivers/acpi/pci_mcfg.c|   7 ++
  drivers/pci/controller/dwc/Kconfig |   3 +-
  drivers/pci/controller/dwc/Makefile|   2 +-
  drivers/pci/controller/dwc/pcie-tegra194.c | 102 +
  include/linux/pci-ecam.h   |   1 +
  5 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index 6b347d9920cc..707181408173 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = {
   THUNDER_ECAM_QUIRK(2, 12),
   THUNDER_ECAM_QUIRK(2, 13),

+ { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, _pcie_ops},
+ { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, _pcie_ops},
+ { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, _pcie_ops},
+ { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, _pcie_ops},
+ { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, _pcie_ops},
+ { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, _pcie_ops},
+
  #define XGENE_V1_ECAM_MCFG(rev, seg) \
   {"APM   ", "XGENE   ", rev, seg, MCFG_BUS_ANY, \
   _v1_pcie_ecam_ops }
diff --git a/drivers/pci/controller/dwc/Kconfig 
b/drivers/pci/controller/dwc/Kconfig
index 0830dfcfa43a..f5b9e75aceed 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -255,7 +255,8 @@ config PCIE_TEGRA194
   select PHY_TEGRA194_P2U
   help
 Say Y here if you want support for DesignWare core based PCIe host
-   controller found in NVIDIA Tegra194 SoC.
+   controller found in NVIDIA Tegra194 SoC. ACPI platforms with Tegra194
+   don't need to enable this.

  config PCIE_UNIPHIER
   bool "Socionext UniPhier PCIe controllers"
diff --git a/drivers/pci/controller/dwc/Makefile 
b/drivers/pci/controller/dwc/Makefile
index 8a637cfcf6e9..76a6c52b8500 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
  obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
  obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
  obj-$(CONFIG_PCI_MESON) += pci-meson.o
-obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
  obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o

  # The following drivers are for devices that use the generic ACPI
@@ -33,4 +32,5 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
  ifdef CONFIG_PCI
  obj-$(CONFIG_ARM64) += pcie-al.o
  obj-$(CONFIG_ARM64) += pcie-hisi.o
+obj-$(CONFIG_ARM64) += pcie-tegra194.o
  endif
diff --git a/drivers/pci/c

Re: Device driver location for the PCIe root port's DMA engine

2021-04-13 Thread Vidya Sagar




On 4/13/2021 11:43 PM, Rob Herring wrote:

External email: Use caution opening links or attachments


On Mon, Apr 12, 2021 at 12:01 PM Vidya Sagar  wrote:


Hi
I'm starting this mail to seek advice on the best approach to be taken
to add support for the driver of the PCIe root port's DMA engine.
To give some background, Tegra194's PCIe IPs are dual-mode PCIe IPs i.e.
they work either in the root port mode or in the endpoint mode based on
the boot time configuration.
Since the PCIe hardware IP as such is the same for both (RP and EP)
modes, the DMA engine sub-system of the PCIe IP is also made available
to both modes of operation.
Typically, the DMA engine is seen only in the endpoint mode, and that
DMA engine’s configuration registers are made available to the host
through one of its BARs.
In the situation that we have here, where there is a DMA engine present
as part of the root port, the DMA engine isn’t a typical general-purpose
DMA engine in the sense that it can’t have both source and destination
addresses targeting external memory addresses.
RP’s DMA engine, while doing a write operation,
would always fetch data (i.e. source) from local memory and write it to
the remote memory over PCIe link (i.e. destination would be the BAR of
an endpoint)
whereas while doing a read operation,
would always fetch/read data (i.e. source) from a remote memory over the
PCIe link and write it to the local memory.

I see that there are at least two ways we can have a driver for this DMA
engine.
a) DMA engine driver as one of the port service drivers
 Since the DMA engine is a part of the root port hardware itself
(although it is not part of the standard capabilities of the root port),
it is one of the options to have the driver for the DMA engine go as one
of the port service drivers (along with AER, PME, hot-plug, etc...).
Based on Vendor-ID and Device-ID matching runtime, either it gets
binded/enabled (like in the case of Tegra194) or it doesn't.
b) DMA engine driver as a platform driver
 The DMA engine hardware can be described as a sub-node under the PCIe
controller's node in the device tree and a separate platform driver can
be written to work with it.


DT expects PCI bridge child nodes to be a PCI device. We've already
broken that with the interrupt controller child nodes, but I don't
really want to add more.
Understood. Is there any other way of specifying the DMA functionality 
other than as a child node so that it is inline with the DT framework's 
expectations?





I’m inclined to have the DMA engine driver as a port service driver as
it makes it cleaner and also in line with the design philosophy (the way
I understood it) of the port service drivers.
Please let me know your thoughts on this.


What is the actual usecase and benefit for using the DMA engine with
the RP? The only one I've come up with is the hardware designers think
having DMA is better than not having DMA so they include that option
on the DWC controller.
In Tegra194-to-Tegra194 configuration (with one Tegra194 as RP and the 
other as EP) better performance is expected when DMA engines on both 
sides are used for pushing(writing) the data across instead of using 
only the EP's DMA engine for both push(write) and pull(read).




Rob



Re: Device driver location for the PCIe root port's DMA engine

2021-04-13 Thread Vidya Sagar




On 4/13/2021 3:23 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


[+cc Matthew for portdrv comment]

On Mon, Apr 12, 2021 at 10:31:02PM +0530, Vidya Sagar wrote:

Hi
I'm starting this mail to seek advice on the best approach to be taken to
add support for the driver of the PCIe root port's DMA engine.
To give some background, Tegra194's PCIe IPs are dual-mode PCIe IPs i.e.
they work either in the root port mode or in the endpoint mode based on the
boot time configuration.
Since the PCIe hardware IP as such is the same for both (RP and EP) modes,
the DMA engine sub-system of the PCIe IP is also made available to both
modes of operation.
Typically, the DMA engine is seen only in the endpoint mode, and that DMA
engine’s configuration registers are made available to the host through one
of its BARs.
In the situation that we have here, where there is a DMA engine present as
part of the root port, the DMA engine isn’t a typical general-purpose DMA
engine in the sense that it can’t have both source and destination addresses
targeting external memory addresses.
RP’s DMA engine, while doing a write operation,
would always fetch data (i.e. source) from local memory and write it to the
remote memory over PCIe link (i.e. destination would be the BAR of an
endpoint)
whereas while doing a read operation,
would always fetch/read data (i.e. source) from a remote memory over the
PCIe link and write it to the local memory.

I see that there are at least two ways we can have a driver for this DMA
engine.
a) DMA engine driver as one of the port service drivers
   Since the DMA engine is a part of the root port hardware itself (although
it is not part of the standard capabilities of the root port), it is one of
the options to have the driver for the DMA engine go as one of the port
service drivers (along with AER, PME, hot-plug, etc...). Based on Vendor-ID
and Device-ID matching runtime, either it gets binded/enabled (like in the
case of Tegra194) or it doesn't.
b) DMA engine driver as a platform driver
   The DMA engine hardware can be described as a sub-node under the PCIe
controller's node in the device tree and a separate platform driver can be
written to work with it.

I’m inclined to have the DMA engine driver as a port service driver as it
makes it cleaner and also in line with the design philosophy (the way I
understood it) of the port service drivers.
Please let me know your thoughts on this.


Personally I'm not a fan of the port service driver model.  It creates
additional struct devices for things that are not separate devices.
And it creates a parallel hierarchy in /sys/bus/pci_express/devices/
that I think does not accurately model the hardware.

Agree.



The existing port services (AER, DPC, hotplug, etc) are things the
device advertises via the PCI Capabilities defined by the generic PCIe
spec, and in my opinion the support for them should be directly part
of the PCI core and activated when the relevant Capability is present.
Is there an on-going activity to remove port service drivers are move 
AER/DPC/Hotplug etc.. handling within PCI core?




The DMA engine is different -- this is device-specific functionality
and I think the obvious way to discover it and bind a driver to it is
via the PCI Vendor and Device ID.

This *is* complicated by the fact that you can't just use
pci_register_driver() to claim functionality implemented in Root Ports
or Switch Ports because portdrv binds to them before you have a
chance.  I think that's a defect in the portdrv design.  The usual
Yes. Hence I was thinking of adding a service driver for the DMA 
functionality



workaround is to use pci_get_device(), which has its own issues (it's
ugly, it's outside the normal driver binding model, doesn't work
nicely with hotplug or udev, doesn't coordinate with other drivers
using the same device, etc).  There are many examples of this in the
EDAC code.
I didn't think of approaching this issue in this way. Thanks for the 
pointers to EDAC code. I'll wait for comments from Matthew before I 
proceed with this approach.




Bjorn



Device driver location for the PCIe root port's DMA engine

2021-04-12 Thread Vidya Sagar

Hi
I'm starting this mail to seek advice on the best approach to be taken 
to add support for the driver of the PCIe root port's DMA engine.
To give some background, Tegra194's PCIe IPs are dual-mode PCIe IPs i.e. 
they work either in the root port mode or in the endpoint mode based on 
the boot time configuration.
Since the PCIe hardware IP as such is the same for both (RP and EP) 
modes, the DMA engine sub-system of the PCIe IP is also made available 
to both modes of operation.
Typically, the DMA engine is seen only in the endpoint mode, and that 
DMA engine’s configuration registers are made available to the host 
through one of its BARs.
In the situation that we have here, where there is a DMA engine present 
as part of the root port, the DMA engine isn’t a typical general-purpose 
DMA engine in the sense that it can’t have both source and destination 
addresses targeting external memory addresses.

RP’s DMA engine, while doing a write operation,
would always fetch data (i.e. source) from local memory and write it to 
the remote memory over PCIe link (i.e. destination would be the BAR of 
an endpoint)

whereas while doing a read operation,
would always fetch/read data (i.e. source) from a remote memory over the 
PCIe link and write it to the local memory.


I see that there are at least two ways we can have a driver for this DMA 
engine.

a) DMA engine driver as one of the port service drivers
	Since the DMA engine is a part of the root port hardware itself 
(although it is not part of the standard capabilities of the root port), 
it is one of the options to have the driver for the DMA engine go as one 
of the port service drivers (along with AER, PME, hot-plug, etc...). 
Based on Vendor-ID and Device-ID matching runtime, either it gets 
binded/enabled (like in the case of Tegra194) or it doesn't.

b) DMA engine driver as a platform driver
	The DMA engine hardware can be described as a sub-node under the PCIe 
controller's node in the device tree and a separate platform driver can 
be written to work with it.


I’m inclined to have the DMA engine driver as a port service driver as 
it makes it cleaner and also in line with the design philosophy (the way 
I understood it) of the port service drivers.

Please let me know your thoughts on this.

Thanks,
Vidya Sagar



Re: RFC: sysfs node for Secondary PCI bus reset (PCIe Hot Reset)

2021-03-11 Thread Vidya Sagar




On 3/3/2021 11:26 PM, Pali Rohár wrote:

External email: Use caution opening links or attachments


On Tuesday 02 March 2021 12:58:29 Alex Williamson wrote:

On Mon, 1 Mar 2021 14:28:17 -0600
Bjorn Helgaas  wrote:


[+cc Alex, reset expert]

On Mon, Mar 01, 2021 at 06:12:21PM +0100, Pali Rohár wrote:

Hello!

PCIe card can be reset via in-band Hot Reset signal which can be
triggered by PCIe bridge via Secondary Bus Reset bit in PCI config
space.

Kernel already exports sysfs node "reset" for triggering Functional
Reset of particular function of PCI device. But in some cases Functional
Reset is not enough and Hot Reset is required.

Following RFC patch exports sysfs node "reset_bus" for PCI bridges which
triggers Secondary Bus Reset and therefore for PCIe bridges it resets
connected PCIe card.

What do you think about it?

Currently there is userspace script which can trigger PCIe Hot Reset by
modifying PCI config space from userspace:

https://alexforencich.com/wiki/en/pcie/hot-reset-linux

But because kernel already provides way how to trigger Functional Reset
it could provide also way how to trigger PCIe Hot Reset.


What that script does and what this does, or what the existing reset
attribute does, are very different.  The script finds the upstream
bridge for a given device, removes the device (ignoring that more than
one device might be affected by the bus reset), uses setpci to trigger
a secondary bus reset, then rescans devices.  The below only triggers
the secondary bus reset, neither saving and restoring affected device
state like the existing function level reset attribute, nor removing
and rescanning as the script does.  It simply leaves an entire
hierarchy of PCI devices entirely un-programmed yet still has struct
pci_devs attached to them for untold future misery.

In fact, for the case of a single device affected by the bus reset, as
intended by the script, the existing reset attribute will already do
that if the device supports no other reset mechanism.  There's actually
a running LFX mentorship project that aims to allow the user to control
the type of reset performed by the existing reset attribute such that a
user could force the bus reset behavior over other reset methods.


Hello Alex? Do you have a link for this "reset" project? I'm interesting
in it as I'm dealing with Compex wifi cards which are causing problems.

For correct initialization I need to issue PCIe Warm Reset for these
cards (Warm Reset is done via PERST# pin which most linux controller
drivers controls via GPIO subsystem). And for now there is no way to
trigger PCIe Warm Reset for particular PCIe device from userspace. As
there is no userspace <--> kernel API for it.


There might be some justification for an attribute that actually
implements the referenced script correctly, perhaps in kernel we could
avoid races with bus rescans, but simply triggering an SBR to quietly
de-program all downstream devices with no state restore or device
rescan is not it.  Any affected device would be unusable.  Was this
tested?  Thanks,


I have tested my change. First I called 'remove' attribute for PCIe
card, then I called this 'bus_reset' on parent PCIe bridge and later I
called 'rescan' attribute on bridge. It correctly rested tested ath9k
card. So I did something similar as in above script. But I agree that
there are race conditions and basically lot of other calls needs to be
done to restore state.

So I see that to make it 'usable' we need to do it automatically in
kernel and also rescan/restore state of PCIe devices behind bridge after
reset...
But, is save-restore alone going to be enough? I mean what is the state 
of the device-driver going to be when the device is going through the 
reset process? Isn't remove-rescan the correct thing to do here rather 
than save/restore?


- Vidya Sagar



Alex


diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 50fcb62d59b5..f5e11c589498 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1321,6 +1321,30 @@ static ssize_t reset_store(struct device *dev, struct 
device_attribute *attr,

  static DEVICE_ATTR(reset, 0200, NULL, reset_store);

+static ssize_t reset_bus_store(struct device *dev, struct device_attribute 
*attr,
+const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned long val;
+ ssize_t result = kstrtoul(buf, 0, );
+
+ if (result < 0)
+ return result;
+
+ if (val != 1)
+ return -EINVAL;
+
+ pm_runtime_get_sync(dev);
+ result = pci_bridge_secondary_bus_reset(pdev);
+ pm_runtime_put(dev);
+ if (result < 0)
+ return result;
+
+ return count;
+}
+
+static DEVICE_ATTR(reset_bus, 0200, NULL, reset_bus_store);
+
  static int pci_create_capabilities_sysfs(struct pci_dev *dev)
  {
   int retval;
@@ -1332,8 +1356,15 @@ static int pci_create_capabilities_sysfs(struct pci_dev 
*dev)
   if (retval)
 

Re: [PATCH] PCI: tegra: Disable PTM capabilities for EP mode

2021-03-05 Thread Vidya Sagar




On 3/5/2021 5:49 PM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Fri, Mar 05, 2021 at 01:42:34PM +0530, Om Prakash Singh wrote:

PCIe EP compliance expect PTM capabilities (ROOT_CAPABLE, RES_CAPABLE,
CLK_GRAN) to be disabled.


I guess this is just enforcing the PCIe spec requirements that only
Root Ports, RCRBs, and Switches are allowed to set the PTM Responder
Capable bit, and that the Local Clock Granularity is RsvdP if PTM Root
Capable is zero?  (PCIe r5.0, sec 7.9.16.2)

Should this be done more generally somewhere in the dwc code as
opposed to in the tegra code?

Agree.




Signed-off-by: Om Prakash Singh 
---
  drivers/pci/controller/dwc/pcie-tegra194.c | 17 -
  include/uapi/linux/pci_regs.h  |  1 +
  2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 6fa216e..a588312 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1639,7 +1639,7 @@ static void pex_ep_event_pex_rst_deassert(struct 
tegra_pcie_dw *pcie)
   struct dw_pcie *pci = >pci;
   struct dw_pcie_ep *ep = >ep;
   struct device *dev = pcie->dev;
- u32 val;
+ u32 val, ptm_cap_base = 0;


Unnecessary init.


   int ret;

   if (pcie->ep_state == EP_STATE_ENABLED)
@@ -1760,6 +1760,21 @@ static void pex_ep_event_pex_rst_deassert(struct 
tegra_pcie_dw *pcie)
 PCI_CAP_ID_EXP);
   clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);

+ /* Disable PTM root and responder capability */
+ ptm_cap_base = dw_pcie_find_ext_capability(>pci,
+PCI_EXT_CAP_ID_PTM);
+ if (ptm_cap_base) {
+ dw_pcie_dbi_ro_wr_en(pci);
+ val = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
+ val &= ~PCI_PTM_CAP_ROOT;
+ dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, val);
+
+ val = dw_pcie_readl_dbi(pci, ptm_cap_base + PCI_PTM_CAP);
+ val &= ~(PCI_PTM_CAP_RES | PCI_PTM_GRANULARITY_MASK);

Why can't this be clubbed with "val &= ~PCI_PTM_CAP_ROOT;" ?


+ dw_pcie_writel_dbi(pci, ptm_cap_base + PCI_PTM_CAP, val);
+ dw_pcie_dbi_ro_wr_dis(pci);
+ }
+
   val = (ep->msi_mem_phys & MSIX_ADDR_MATCH_LOW_OFF_MASK);
   val |= MSIX_ADDR_MATCH_LOW_OFF_EN;
   dw_pcie_writel_dbi(pci, MSIX_ADDR_MATCH_LOW_OFF, val);
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index e709ae8..9dd6f8d 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1050,6 +1050,7 @@
  /* Precision Time Measurement */
  #define PCI_PTM_CAP  0x04/* PTM Capability */
  #define  PCI_PTM_CAP_REQ 0x0001  /* Requester capable */
+#define  PCI_PTM_CAP_RES 0x0002  /* Responder capable */
  #define  PCI_PTM_CAP_ROOT0x0004  /* Root capable */
  #define  PCI_PTM_GRANULARITY_MASK0xFF00  /* Clock granularity */
  #define PCI_PTM_CTRL 0x08/* PTM Control */
--
2.7.4



Re: [PATCH] arm64: PCI: Enable SMC conduit

2021-01-12 Thread Vidya Sagar




On 1/5/2021 10:27 AM, Jeremy Linton wrote:

External email: Use caution opening links or attachments


Given that most arm64 platform's PCI implementations needs quirks
to deal with problematic config accesses, this is a good place to
apply a firmware abstraction. The ARM PCI SMMCCC spec details a
standard SMC conduit designed to provide a simple PCI config
accessor. This specification enhances the existing ACPI/PCI
abstraction and expects power, config, etc functionality is handled
by the platform. It also is very explicit that the resulting config
space registers must behave as is specified by the pci specification.

Lets hook the normal ACPI/PCI config path, and when we detect
missing MADT data, attempt to probe the SMC conduit. If the conduit
exists and responds for the requested segment number (provided by the
ACPI namespace) attach a custom pci_ecam_ops which redirects
all config read/write requests to the firmware.

This patch is based on the Arm PCI Config space access document @
https://developer.arm.com/documentation/den0115/latest

Signed-off-by: Jeremy Linton 
---
  arch/arm64/kernel/pci.c   | 87 +++
  include/linux/arm-smccc.h | 26 
  2 files changed, 113 insertions(+)

diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 1006ed2d7c60..56d3773aaa25 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -7,6 +7,7 @@
   */

  #include 
+#include 
  #include 
  #include 
  #include 
@@ -107,6 +108,90 @@ static int pci_acpi_root_prepare_resources(struct 
acpi_pci_root_info *ci)
 return status;
  }

+static int smccc_pcie_check_conduit(u16 seg)
+{
+   struct arm_smccc_res res;
+
+   if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE)
+   return -EOPNOTSUPP;
+
+   arm_smccc_smc(SMCCC_PCI_VERSION, 0, 0, 0, 0, 0, 0, 0, );
+   if ((int)res.a0 < 0)
+   return -EOPNOTSUPP;
+
+   arm_smccc_smc(SMCCC_PCI_SEG_INFO, seg, 0, 0, 0, 0, 0, 0, );
+   if ((int)res.a0 < 0)
+   return -EOPNOTSUPP;
+
+   pr_info("PCI: SMC conduit attached to segment %d\n", seg);
Shouldn't this print be moved towards the end of 
pci_acpi_setup_smccc_mapping() API?



+
+   return 0;
+}
+
+static int smccc_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+   struct arm_smccc_res res;
+
+   devfn |= bus->number << 8;
+   devfn |= bus->domain_nr << 16;
+
+   arm_smccc_smc(SMCCC_PCI_READ, devfn, where, size, 0, 0, 0, 0, );
+   if (res.a0) {
+   *val = ~0;
+   return -PCIBIOS_BAD_REGISTER_NUMBER;
+   }
+
+   *val = res.a1;
+   return PCIBIOS_SUCCESSFUL;
+}
+
+static int smccc_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
+  int where, int size, u32 val)
+{
+   struct arm_smccc_res res;
+
+   devfn |= bus->number << 8;
+   devfn |= bus->domain_nr << 16;
+
+   arm_smccc_smc(SMCCC_PCI_WRITE, devfn, where, size, val, 0, 0, 0, );
+   if (res.a0)
+   return -PCIBIOS_BAD_REGISTER_NUMBER;
+
+   return PCIBIOS_SUCCESSFUL;
+}
+
+static const struct pci_ecam_ops smccc_pcie_ecam_ops = {
+   .bus_shift  = 8,
+   .pci_ops= {
+   .read   = smccc_pcie_config_read,
+   .write  = smccc_pcie_config_write,
+   }
+};
+
+static struct pci_config_window *
+pci_acpi_setup_smccc_mapping(struct acpi_pci_root *root)
+{
+   struct device *dev = >device->dev;
+   struct resource *bus_res = >secondary;
+   struct pci_config_window *cfg;
+
+   cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+   if (!cfg)
+   return ERR_PTR(-ENOMEM);
+
+   cfg->parent = dev;
+   cfg->ops = _pcie_ecam_ops;
+   cfg->busr.start = bus_res->start;
+   cfg->busr.end = bus_res->end;
+   cfg->busr.flags = IORESOURCE_BUS;
+
+   cfg->res.name = "PCI SMCCC";
+   if (cfg->ops->init)

Since there is no init implemented, what is the purpose of having this?


+   cfg->ops->init(cfg);
+   return cfg;
+}
+
  /*
   * Lookup the bus range for the domain in MCFG, and set up config space
   * mapping.
@@ -125,6 +210,8 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root)

 ret = pci_mcfg_lookup(root, , _ops);
 if (ret) {
+   if (!smccc_pcie_check_conduit(seg))
+   return pci_acpi_setup_smccc_mapping(root);
 dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res);
 return NULL;
 }
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index f860645f6512..327f52533c71 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -89,6 +89,32 @@

  #define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED   1

+/* PCI ECAM conduit */
+#define SMCCC_PCI_VERSION

Re: [PATCH] PCI:tegra:Correct typo for PCIe endpoint mode in Tegra194

2021-01-02 Thread Vidya Sagar

Thanks for the patch.

Acked-by: Vidya Sagar 

On 12/31/2020 8:55 AM, Wesley Sheng wrote:

External email: Use caution opening links or attachments


In config PCIE_TEGRA194_EP the mode incorrectly referred to
host mode.

Signed-off-by: Wesley Sheng 
---
  drivers/pci/controller/dwc/Kconfig | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/Kconfig 
b/drivers/pci/controller/dwc/Kconfig
index 044a3761c44f..6960babe6161 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -273,7 +273,7 @@ config PCIE_TEGRA194_EP
 select PCIE_TEGRA194
 help
   Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
- work in host mode. There are two instances of PCIe controllers in
+ work in endpoint mode. There are two instances of PCIe controllers in
   Tegra194. This controller can work either as EP or RC. In order to
   enable host-specific features PCIE_TEGRA194_HOST must be selected and
   in order to enable device-specific features PCIE_TEGRA194_EP must be
--
2.16.2



[PATCH V3] PCI: dwc: Add support to configure for ECRC

2020-12-30 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V3:
* Rebased on top of linux-next

V2:
* Addressed Bjorn's comments

 drivers/pci/controller/dwc/pcie-designware.c | 48 +++-
 drivers/pci/controller/dwc/pcie-designware.h |  1 +
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index 645fa1892375..5b72a5448d2e 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
+static inline u32 dw_pcie_enable_ecrc(u32 val)
+{
+   /*
+* DesignWare core version 4.90A has this strange design issue
+* where the 'TD' bit in the Control register-1 of the ATU outbound
+* region acts like an override for the ECRC setting i.e. the presence
+* of TLP Digest(ECRC) in the outgoing TLPs is solely determined by
+* this bit. This is contrary to the PCIe spec which says that the
+* enablement of the ECRC is solely determined by the AER registers.
+*
+* Because of this, even when the ECRC is enabled through AER
+* registers, the transactions going through ATU won't have TLP Digest
+* as there is no way the AER sub-system could program the TD bit which
+* is specific to DesignWare core.
+*
+* The best way to handle this scenario is to program the TD bit
+* always. It affects only the traffic from root port to downstream
+* devices.
+*
+* At this point,
+* When ECRC is enabled in AER registers, everything works normally
+* When ECRC is NOT enabled in AER registers, then,
+* on Root Port:- TLP Digest (DWord size) gets appended to each packet
+*even through it is not required. Since downstream
+*TLPs are mostly for configuration accesses and BAR
+*accesses, they are not in critical path and won't
+*have much negative effect on the performance.
+* on End Point:- TLP Digest is received for some/all the packets coming
+*from the root port. TLP Digest is ignored because,
+*as per the PCIe Spec r5.0 v1.0 section 2.2.3
+*"TLP Digest Rules", when an endpoint receives TLP
+*Digest when its ECRC check functionality is disabled
+*in AER registers, received TLP Digest is just ignored.
+* Since there is no issue or error reported either side, best way to
+* handle the scenario is to program TD bit by default.
+*/
+
+   return val | PCIE_ATU_TD;
+}
+
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
@@ -248,6 +288,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
val = type | PCIE_ATU_FUNC_NUM(func_no);
val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 PCIE_ATU_ENABLE);
@@ -294,8 +336,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
+   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 0207840756c4..5d979953800d 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -86,6 +86,7 @@
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
 #define PCIE_ATU_TYPE_CFG1 0x5
+#define PCIE_ATU_TDBIT(8)
 #define PCIE

Re: Commit 4257f7e0 ("PCI/ASPM: Save/restore L1SS Capability for suspend/resume") causing hibernate resume failures

2020-12-29 Thread Vidya Sagar

Ideally Bjorn's patch should have worked.
Could you please collect 'sudo lspci -vv' (please don't forget to give 
sudo) with Bjorn's patch before and after hibernate?
Also, is it right to say that with policy set to "performance" there is 
no issue during hibernate/resume?


- Vidya Sagar

On 12/28/2020 12:00 PM, Kenneth R. Crudup wrote:

External email: Use caution opening links or attachments


On Sun, 27 Dec 2020, Kenneth R. Crudup wrote:


I'll try your patch after the revert and see if anything changes.


I just realized today's patch makes no sense if it's reverted, so nevermind.

 -Kenny

--
Kenneth R. Crudup  Sr. SW Engineer, Scott County Consulting, Orange County CA



Re: dwc: tegra194: issue with card containing a bridge

2020-12-15 Thread Vidya Sagar

Thanks Mian for bringing it to our notice.
Have you tried removing the dw_pcie_setup_rc(pp); call from 
pcie-tegra194.c file on top of linux-next? and does that solve the issue?


diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c

index 5597b2a49598..1c9e9c054592 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -907,7 +907,7 @@ static void tegra_pcie_prepare_host(struct pcie_port 
*pp)
dw_pcie_writel_dbi(pci, 
CFG_TIMER_CTRL_MAX_FUNC_NUM_OFF, val);

}

-   dw_pcie_setup_rc(pp);
+   //dw_pcie_setup_rc(pp);

clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);

I took a quick look at the dw_pcie_setup_rc() implementation and I'm not 
sure why calling it second time should create any issue for the 
enumeration of devices behind a switch. Perhaps I need to spend more 
time to debug that part.
In any case, since dw_pcie_setup_rc() is already part of 
dw_pcie_host_init(), I think it can be removed from 
tegra_pcie_prepare_host() implemention.


Thanks,
Vidya Sagar

On 12/15/2020 3:54 PM, Mian Yousaf Kaukab wrote:

External email: Use caution opening links or attachments


Hi,
I am seeing an issue with next-20201211 with USB3380[1] based PCIe card
(vid:pid 10b5:3380) on Jetson AGX Xavier. Card doesn't show up in the
lspci output.

In non working case (next-20201211):
# lspci
0001:00:00.0 PCI bridge: NVIDIA Corporation Device 1ad2 (rev a1)
0001:01:00.0 SATA controller: Marvell Technology Group Ltd. Device 9171 (rev 13)
0005:00:00.0 PCI bridge: NVIDIA Corporation Device 1ad0 (rev a1)

In working case (v5.10-rc7):
# lspci
0001:00:00.0 PCI bridge: Molex Incorporated Device 1ad2 (rev a1)
0001:01:00.0 SATA controller: Marvell Technology Group Ltd. Device 9171 (rev 13)
0005:00:00.0 PCI bridge: Molex Incorporated Device 1ad0 (rev a1)
0005:01:00.0 PCI bridge: PLX Technology, Inc. Device 3380 (rev ab)
0005:02:02.0 PCI bridge: PLX Technology, Inc. Device 3380 (rev ab)
0005:03:00.0 USB controller: PLX Technology, Inc. Device 3380 (rev ab)
# lspci -t
-+-[0005:00]---00.0-[01-ff]00.0-[02-03]02.0-[03]00.0
  +-[0001:00]---00.0-[01-ff]00.0
  \-[:00]-
#lspci -v
https://paste.opensuse.org/87573209

git-bisect points to commit b9ac0f9dc8ea ("PCI: dwc: Move dw_pcie_setup_rc() to DWC 
common code").
dw_pcie_setup_rc() is not removed from pcie-tegra194.c in this commit.

Could the failure be caused because dw_pcie_setup_rc() is called twice now in 
case of tegra194?

BR,
Yousaf

[1]: 
https://www.broadcom.com/products/pcie-switches-bridges/usb-pci/usb-controllers/usb3380



Re: [PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-12-11 Thread Vidya Sagar

Hi Lorenzo,
Apologies to bug you, but wondering if you have any further comments on 
this patch that I need to take care of?


Thanks,
Vidya Sagar

On 12/3/2020 5:40 PM, Vidya Sagar wrote:



On 11/25/2020 2:32 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Tue, Nov 24, 2020 at 03:50:01PM +0530, Vidya Sagar wrote:

Hi Bjorn,
Please let me know if this patch needs any further modifications


I'm fine with it, but of course Lorenzo will take care of it.

Thanks Bjorn.

Hi Lorenzo,
Please let me know if you have any comments for this patch.

Thanks,
Vidya Sagar




On 11/12/2020 10:32 PM, Vidya Sagar wrote:

External email: Use caution opening links or attachments


On 11/12/2020 3:59 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Wed, Nov 11, 2020 at 10:21:46PM +0530, Vidya Sagar wrote:



On 11/11/2020 9:57 PM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 11/11/20, 7:12 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in
one of the control
registers of ATU. This bit also needs to be programmed for 
proper ECRC

functionality. This is currently identified as an issue
with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

    drivers/pci/controller/dwc/pcie-designware.c | 52
++--
    drivers/pci/controller/dwc/pcie-designware.h |  1 +
    2 files changed, 49 insertions(+), 4 deletions(-)

diff --git
a/drivers/pci/controller/dwc/pcie-designware.c
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void
dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index,
u32 reg,
 dw_pcie_writel_atu(pci, offset + reg, val);
    }

+static inline u32 dw_pcie_enable_ecrc(u32 val)


What is the reason to use inline here?


Actually, I wanted to move the programming part inside the
respective APIs
but then I wanted to give some details as well in comments so to 
avoid
duplication, I came up with this function. But, I'm making it 
inline for

better code optimization by compiler.


I don't really care either way, but I'd be surprised if the compiler
didn't inline this all by itself even without the explicit "inline".

I just checked it and you are right that compiler is indeed inlining it
without explicitly mentioning 'inline'.
I hope it is ok to leave it that way.




+{
+ /*
+  * DesignWare core version 4.90A has this strange design 
issue

+  * where the 'TD' bit in the Control register-1 of
the ATU outbound
+  * region acts like an override for the ECRC
setting i.e. the presence
+  * of TLP Digest(ECRC) in the outgoing TLPs is
solely determined by
+  * this bit. This is contrary to the PCIe spec
which says that the
+  * enablement of the ECRC is solely determined by
the AER registers.
+  *
+  * Because of this, even when the ECRC is enabled through AER
+  * registers, the transactions going through ATU
won't have TLP Digest
+  * as there is no way the AER sub-system could
program the TD bit which
+  * is specific to DesignWare core.
+  *
+  * The best way to handle this scenario is to program the 
TD bit

+  * always. It affects only the traffic from root
port to downstream
+  * devices.
+  *
+  * At this point,
+  * When ECRC is enabled in AER registers,
everything works normally
+  * When ECRC is NOT enabled in AER registers, then,
+  * on Root Port:- TLP Digest (DWord size) gets
appended to each packet
+  *    even through it is not required.
Since downstream
+  *    TLPs are mostly for
configuration accesses and BAR
+  *    accesses, they are not in
critical path and won't
+  *    have much negative effect on the 
performance.

+  * on End Point:- TLP Digest is received for
some/all the packets coming
+  *    from the root port. TLP Digest
is ignored because,
+  *    as per the PCIe Spec r5.0 v1.0 section 
2.2.3

+  *    "TLP Digest Rules", when an
endpoint receives TLP
+  *    Digest when its ECRC check
functionality is disabled
+  *    in AER registers, received TLP
Digest is just ignored.
+  * Since there is no issue or error reported
either side, best way to
+  * handle the scenario is to program TD bit by default.
+  */
+
+ return val | PCIE_ATU_TD;
+}


Re: [PATCH] PCI: Save/restore L1 PM Substate extended capability registers

2020-12-08 Thread Vidya Sagar

There is a change already available for it in linux-next
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=4257f7e008ea394fcecc050f1569c3503b8bcc15

Thanks,
Vidya Sagar

On 12/9/2020 3:36 AM, David E. Box wrote:

External email: Use caution opening links or attachments


On Intel systems that support ACPI Low Power Idle it has been observed
that the L1 Substate capability can return disabled after a s2idle
cycle. This causes the loss of L1 Substate support during runtime
leading to higher power consumption. Add save/restore of the L1SS
control registers.

Signed-off-by: David E. Box 
---
  drivers/pci/pci.c | 49 +++
  1 file changed, 49 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e578d34095e9..beee3d9952a6 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1539,6 +1539,48 @@ static void pci_restore_ltr_state(struct pci_dev *dev)
 pci_write_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, *cap++);
  }

+static void pci_save_l1ss_state(struct pci_dev *dev)
+{
+   int l1ss;
+   struct pci_cap_saved_state *save_state;
+   u16 *cap;
+
+   if (!pci_is_pcie(dev))
+   return;
+
+   l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!l1ss)
+   return;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state) {
+   pci_err(dev, "no suspend buffer for L1 Substates\n");
+   return;
+   }
+
+   cap = (u16 *)_state->cap.data[0];
+   pci_read_config_word(dev, l1ss + PCI_L1SS_CTL1, cap++);
+   pci_read_config_word(dev, l1ss + PCI_L1SS_CTL1 + 2, cap++);
+   pci_read_config_word(dev, l1ss + PCI_L1SS_CTL2, cap++);
+}
+
+static void pci_restore_l1ss_state(struct pci_dev *dev)
+{
+   struct pci_cap_saved_state *save_state;
+   int l1ss;
+   u16 *cap;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state || !l1ss)
+   return;
+
+   cap = (u16 *)_state->cap.data[0];
+   pci_write_config_word(dev, l1ss + PCI_L1SS_CTL1, *cap++);
+   pci_write_config_word(dev, l1ss + PCI_L1SS_CTL1 + 2, *cap++);
+   pci_write_config_word(dev, l1ss + PCI_L1SS_CTL2, *cap++);
+}
+
  /**
   * pci_save_state - save the PCI configuration space of a device before
   * suspending
@@ -1563,6 +1605,7 @@ int pci_save_state(struct pci_dev *dev)
 if (i != 0)
 return i;

+   pci_save_l1ss_state(dev);
 pci_save_ltr_state(dev);
 pci_save_dpc_state(dev);
 pci_save_aer_state(dev);
@@ -1670,6 +1713,7 @@ void pci_restore_state(struct pci_dev *dev)
  */
 pci_restore_ltr_state(dev);

+   pci_restore_l1ss_state(dev);
 pci_restore_pcie_state(dev);
 pci_restore_pasid_state(dev);
 pci_restore_pri_state(dev);
@@ -3332,6 +3376,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
 if (error)
 pci_err(dev, "unable to allocate suspend buffer for LTR\n");

+   error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
+   3 * sizeof(u16));
+   if (error)
+   pci_err(dev, "unable to allocate suspend buffer for L1 
Substates\n");
+
 pci_allocate_vc_save_buffers(dev);
  }

--
2.20.1



Re: [PATCH V5 5/5] PCI: tegra: Disable LTSSM during L2 entry

2020-12-07 Thread Vidya Sagar




On 12/8/2020 2:07 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


[+cc Jingoo, Gustavo]

On Thu, Dec 03, 2020 at 07:04:51PM +0530, Vidya Sagar wrote:

PCIe cards like Marvell SATA controller and some of the Samsung NVMe
drives don't support taking the link to L2 state. When the link doesn't
go to L2 state, Tegra194 requires the LTSSM to be disabled to allow PHY
to start the next link up process cleanly during suspend/resume sequence.
Failing to disable LTSSM results in the PCIe link not coming up in the
next resume cycle.


Is this a Tegra194-specific issue, or will other DWC-based controllers
need a similar change?

This is a Tegra194 specific issue.

Thanks,
Vidya Sagar



Tested-by: Thierry Reding 
Signed-off-by: Vidya Sagar 
Acked-by: Thierry Reding 
---
V5:
* Added Tested-by and Acked-by from Thierry Reding

V4:
* New patch in this series

  drivers/pci/controller/dwc/pcie-tegra194.c | 16 +---
  1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index f4109d71f20b..5597b2a49598 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1506,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
   data &= ~APPL_PINMUX_PEX_RST;
   appl_writel(pcie, data, APPL_PINMUX);

+ /*
+  * Some cards do not go to detect state even after de-asserting
+  * PERST#. So, de-assert LTSSM to bring link to detect state.
+  */
+ data = readl(pcie->appl_base + APPL_CTRL);
+ data &= ~APPL_CTRL_LTSSM_EN;
+ writel(data, pcie->appl_base + APPL_CTRL);
+
   err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
   data,
   ((data &
@@ -1513,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
   APPL_DEBUG_LTSSM_STATE_SHIFT) ==
   LTSSM_STATE_PRE_DETECT,
   1, LTSSM_TIMEOUT);
- if (err) {
+ if (err)
   dev_info(pcie->dev, "Link didn't go to detect state\n");
- } else {
- /* Disable LTSSM after link is in detect state */
- data = appl_readl(pcie, APPL_CTRL);
- data &= ~APPL_CTRL_LTSSM_EN;
- appl_writel(pcie, data, APPL_CTRL);
- }
   }
   /*
* DBI registers may not be accessible after this as PLL-E would be
--
2.17.1



Re: [PATCH V2] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-12-03 Thread Vidya Sagar




On 12/4/2020 1:24 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Fri, Dec 04, 2020 at 12:33:45AM +0530, Vidya Sagar wrote:

On 12/3/2020 11:54 PM, Bjorn Helgaas wrote:

On Tue, Nov 24, 2020 at 04:20:35PM +0530, Vidya Sagar wrote:

There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register. Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.


This seems good to me.  I'll post a possible revision to set
dev->no_64bit_msi in the device enumeration path instead of in the IRQ
allocation path, since it's really a property of the device, not of
the msi_desc.

I like the extra checking this gives us.  Was this prompted by
tripping over something, or is it something you noticed by code
reading?  If the former, a hint about what was wrong and how it's
being fixed would be useful.

I observed functionality issue with Marvell SATA controller (1b4b:9171) when
the allocated MSI target address was a 64-bit address. I mentioned the
Marvell SATA controller as an example in the commit message.


I know you mentioned the Marvell controller, but apparently that
device is working perfectly correctly: it does not support 64-bit MSI,
and it does not advertise support for 64-bit MSI.

So if there's a functionality issue, that means something is wrong in
Linux that caused us to assign a 64-bit MSI address to it.  *That*
issue is what I want to know about.  Your patch only warns about the
issue; it doesn't fix it.
The issue is in the DWC code. I pushed a generic patch to fix that issue 
by specifying the limit of MSI target address to 32-bit region. Patch is 
up for review at 
http://patchwork.ozlabs.org/project/linux-pci/patch/20201117165312.25847-1-vid...@nvidia.com/




I don't think there's any point in specifically mentioning the Marvell
device if it is working correctly, because the same issue should
affect *any* device that doesn't support 64-bit MSI.  But if there's
some arch code that incorrectly assigns a 64-bit address, it would
definitely be useful to specify the arch.  And hopefully there's a fix
for that arch code, too.


Signed-off-by: Vidya Sagar 
---
V2:
* Addressed Bjorn's comment and changed the error message

   drivers/pci/msi.c | 11 +++
   1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..8de5ba6b4a59 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
entry->msi_attrib.multiple  = ilog2(__roundup_pow_of_two(nvec));

- if (control & PCI_MSI_FLAGS_64BIT)
+ if (control & PCI_MSI_FLAGS_64BIT) {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
- else
+ } else {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+ dev->no_64bit_msi = 1;
+ }

/* Save the initial mask status */
if (entry->msi_attrib.maskbit)
@@ -602,8 +604,9 @@ static int msi_verify_entries(struct pci_dev *dev)
for_each_pci_msi_entry(entry, dev) {
if (!dev->no_64bit_msi || !entry->msg.address_hi)
continue;
- pci_err(dev, "Device has broken 64-bit MSI but arch"
- " tried to assign one above 4G\n");
+ pci_err(dev, "Device has either broken 64-bit MSI or "
+ "only 32-bit MSI support but "
+ "arch tried to assign one above 4G\n");
return -EIO;
}
return 0;
--
2.17.1



Re: [PATCH V2] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-12-03 Thread Vidya Sagar




On 12/3/2020 11:54 PM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Tue, Nov 24, 2020 at 04:20:35PM +0530, Vidya Sagar wrote:

There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register. Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.


This seems good to me.  I'll post a possible revision to set
dev->no_64bit_msi in the device enumeration path instead of in the IRQ
allocation path, since it's really a property of the device, not of
the msi_desc.

I like the extra checking this gives us.  Was this prompted by
tripping over something, or is it something you noticed by code
reading?  If the former, a hint about what was wrong and how it's
being fixed would be useful.
I observed functionality issue with Marvell SATA controller (1b4b:9171) 
when the allocated MSI target address was a 64-bit address. I mentioned 
the Marvell SATA controller as an example in the commit message.


Thanks,
Vidya Sagar




Signed-off-by: Vidya Sagar 
---
V2:
* Addressed Bjorn's comment and changed the error message

  drivers/pci/msi.c | 11 +++
  1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..8de5ba6b4a59 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
   entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
   entry->msi_attrib.multiple  = ilog2(__roundup_pow_of_two(nvec));

- if (control & PCI_MSI_FLAGS_64BIT)
+ if (control & PCI_MSI_FLAGS_64BIT) {
   entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
- else
+ } else {
   entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+ dev->no_64bit_msi = 1;
+ }

   /* Save the initial mask status */
   if (entry->msi_attrib.maskbit)
@@ -602,8 +604,9 @@ static int msi_verify_entries(struct pci_dev *dev)
   for_each_pci_msi_entry(entry, dev) {
   if (!dev->no_64bit_msi || !entry->msg.address_hi)
   continue;
- pci_err(dev, "Device has broken 64-bit MSI but arch"
- " tried to assign one above 4G\n");
+ pci_err(dev, "Device has either broken 64-bit MSI or "
+ "only 32-bit MSI support but "
+ "arch tried to assign one above 4G\n");
   return -EIO;
   }
   return 0;
--
2.17.1



[PATCH V5 3/5] PCI: tegra: Continue unconfig sequence even if parts fail

2020-12-03 Thread Vidya Sagar
Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.

Tested-by: Thierry Reding 
Signed-off-by: Vidya Sagar 
Acked-by: Thierry Reding 
---
V5:
* Added Tested-by and Acked-by from Thierry Reding

V4:
* None

V3:
* Modified subject as per Bjorn's suggestion
* Removed tegra_pcie_init_controller()'s error checking part and pushed
  a separate patch for it

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 39 +-
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 59163b735c96..471c6d725c70 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1415,43 +1415,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
int ret;
 
ret = reset_control_assert(pcie->core_rst);
-   if (ret) {
-   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-   ret);
-   return ret;
-   }
+   if (ret)
+   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", 
ret);
 
tegra_pcie_disable_phy(pcie);
 
ret = reset_control_assert(pcie->core_apb_rst);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-   return ret;
-   }
 
clk_disable_unprepare(pcie->core_clk);
 
ret = regulator_disable(pcie->pex_ctl_supply);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-   return ret;
-   }
 
tegra_pcie_disable_slot_regulators(pcie);
 
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
-   return ret;
-   }
-
-   return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1475,7 +1464,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1544,13 +1534,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(>pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
-
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -2197,8 +2186,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
   PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 
-   return __deinit_controller(pcie);
+   return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2226,7 +2216,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2264,7 +2255,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device 
*pdev)
disable_irq(pcie->pci.pp.msi_irq);
 
tegra_pcie_dw_pme_turnoff(pcie);
-   __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
-- 
2.17.1



[PATCH V5 4/5] PCI: tegra: Check return value of tegra_pcie_init_controller()

2020-12-03 Thread Vidya Sagar
The return value of tegra_pcie_init_controller() must be checked before
PCIe link up check and registering debugfs entries subsequently as it
doesn't make sense to do these when the controller initialization itself
has failed.

Tested-by: Thierry Reding 
Signed-off-by: Vidya Sagar 
Acked-by: Thierry Reding 
---
V5:
* Added Tested-by and Acked-by from Thierry Reding

V4:
* None

V3:
* New patch in this series

 drivers/pci/controller/dwc/pcie-tegra194.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 471c6d725c70..f4109d71f20b 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1563,7 +1563,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
goto fail_pm_get_sync;
}
 
-   tegra_pcie_init_controller(pcie);
+   ret = tegra_pcie_init_controller(pcie);
+   if (ret < 0) {
+   dev_err(dev, "Failed to initialize controller: %d\n", ret);
+   goto fail_pm_get_sync;
+   }
 
pcie->link_state = tegra_pcie_dw_link_up(>pci);
if (!pcie->link_state) {
-- 
2.17.1



[PATCH V5 2/5] PCI: tegra: Set DesignWare IP version

2020-12-03 Thread Vidya Sagar
Set the DesignWare IP version for Tegra194 to 0x490A. This would be used
by the DesigWare sub-system to do any version specific configuration
(Ex:- TD bit programming for ECRC).

Tested-by: Thierry Reding 
Signed-off-by: Vidya Sagar 
Acked-by: Thierry Reding 
---
V5:
* Added Tested-by and Acked-by from Thierry Reding

V4:
* None

V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 4c966e9adb2b..59163b735c96 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1984,6 +1984,7 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
pci->ops = _dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
+   pci->version = 0x490A;
 
pp = >pp;
pp->num_vectors = MAX_MSI_IRQS;
-- 
2.17.1



[PATCH V5 5/5] PCI: tegra: Disable LTSSM during L2 entry

2020-12-03 Thread Vidya Sagar
PCIe cards like Marvell SATA controller and some of the Samsung NVMe
drives don't support taking the link to L2 state. When the link doesn't
go to L2 state, Tegra194 requires the LTSSM to be disabled to allow PHY
to start the next link up process cleanly during suspend/resume sequence.
Failing to disable LTSSM results in the PCIe link not coming up in the
next resume cycle.

Tested-by: Thierry Reding 
Signed-off-by: Vidya Sagar 
Acked-by: Thierry Reding 
---
V5:
* Added Tested-by and Acked-by from Thierry Reding

V4:
* New patch in this series

 drivers/pci/controller/dwc/pcie-tegra194.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index f4109d71f20b..5597b2a49598 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1506,6 +1506,14 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX);
 
+   /*
+* Some cards do not go to detect state even after de-asserting
+* PERST#. So, de-assert LTSSM to bring link to detect state.
+*/
+   data = readl(pcie->appl_base + APPL_CTRL);
+   data &= ~APPL_CTRL_LTSSM_EN;
+   writel(data, pcie->appl_base + APPL_CTRL);
+
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
data,
((data &
@@ -1513,14 +1521,8 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
LTSSM_STATE_PRE_DETECT,
1, LTSSM_TIMEOUT);
-   if (err) {
+   if (err)
dev_info(pcie->dev, "Link didn't go to detect state\n");
-   } else {
-   /* Disable LTSSM after link is in detect state */
-   data = appl_readl(pcie, APPL_CTRL);
-   data &= ~APPL_CTRL_LTSSM_EN;
-   appl_writel(pcie, data, APPL_CTRL);
-   }
}
/*
 * DBI registers may not be accessible after this as PLL-E would be
-- 
2.17.1



[PATCH V5 0/5] Enhancements to Tegra194 PCIe driver

2020-12-03 Thread Vidya Sagar
This series of patches do some enhancements and some bug fixes to the
Tegra194 PCIe platform driver like
- Fix Vendor-ID corruption
- Update DWC IP version
- Continue with uninitialization sequence even if parts fail
- Check return value of tegra_pcie_init_controller()
- Disable LTSSM during link's L2 entry

V5:
* Rebased the first patch in the series
* Dropped the second patch
* Added Tested-by and Acked-by for rest of the patches

V4:
* Added a new patch to address link-up issues with some of the cards

V3:
* Addressed Bjorn's review comments
* Split earlier patch-4 into two
  - Continue with the uninitialization sequence even if some parts fail
  - Check return value of tegra_pcie_init_controller() and exit accordingly

V2:
* Addressed Rob's comments. Changed 'Strongly Ordered' to 'nGnRnE'

Vidya Sagar (5):
  PCI: tegra: Fix ASPM-L1SS advertisement disable code
  PCI: tegra: Set DesignWare IP version
  PCI: tegra: Continue unconfig sequence even if parts fail
  PCI: tegra: Check return value of tegra_pcie_init_controller()
  PCI: tegra: Disable LTSSM during L2 entry

 drivers/pci/controller/dwc/pcie-tegra194.c | 74 +++---
 1 file changed, 36 insertions(+), 38 deletions(-)

-- 
2.17.1



[PATCH V5 1/5] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-12-03 Thread Vidya Sagar
If the absence of CLKREQ# signal is indicated by the absence of
"supports-clkreq" in the device-tree node, current driver is disabling
the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States
offset is correctly initialized. Since default value of the ASPM-L1SS
offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2
instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are
not being applied. This patch fixes this issue by refactoring the
code that disables the ASPM-L1SS advertisement.

Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar 
---
V5:
* Rebased on top of the tree code

V4:
* None

V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 648e731bccfa..4c966e9adb2b 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -863,12 +863,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
  PCI_CAP_ID_EXP);
 
-   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
@@ -897,6 +891,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
init_host_aspm(pcie);
 
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
-- 
2.17.1



Re: [PATCH V4 2/6] PCI: tegra: Map configuration space as nGnRnE

2020-12-03 Thread Vidya Sagar





-Original Message-
From: Thierry Reding 
Sent: Thursday, November 26, 2020 5:04 PM
To: Vidya Sagar 
Cc: lorenzo.pieral...@arm.com; robh...@kernel.org; bhelg...@google.com;
Jonathan Hunter ; amanharitsh...@gmail.com;
dinghao@zju.edu.cn; k...@linux.com; linux-...@vger.kernel.org; linux-
te...@vger.kernel.org; linux-kernel@vger.kernel.org; Krishna Thota
; Manikanta Maddireddy ;
sagar...@gmail.com
Subject: Re: [PATCH V4 2/6] PCI: tegra: Map configuration space as nGnRnE

On Mon, Nov 09, 2020 at 10:49:33PM +0530, Vidya Sagar wrote:
> As specified in the comment for pci_remap_cfgspace() define in
> arch/arm64/include/asm/io.h file, PCIe configuration space should be
> mapped as nGnRnE. Hence changing to dev_pci_remap_cfgspace() from
> devm_ioremap_resource() for mapping DBI space as that is nothing but
> the root port's own configuration space.
>
> Signed-off-by: Vidya Sagar 
> ---
> V4:
> * None
>
> V3:
> * None
>
> V2:
> * Changed 'Strongly Ordered' to 'nGnRnE'
>
>  drivers/pci/controller/dwc/pcie-tegra194.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c
> b/drivers/pci/controller/dwc/pcie-tegra194.c
> index b172b1d49713..7a0c64436861 100644
> --- a/drivers/pci/controller/dwc/pcie-tegra194.c
> +++ b/drivers/pci/controller/dwc/pcie-tegra194.c
> @@ -2108,7 +2108,9 @@ static int tegra_pcie_dw_probe(struct
platform_device *pdev)
>}
>pcie->dbi_res = dbi_res;
>
> -  pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
> +  pci->dbi_base = devm_pci_remap_cfgspace(dev,
> +  dbi_res->start,
> +  resource_size(dbi_res));
>if (IS_ERR(pci->dbi_base))
>return PTR_ERR(pci->dbi_base);
>

Similarly to patch 1/6, this is no longer required because it's already part of 
one
of Rob's earlier patches, so this, too, can be dropped.
Yes. This patch is not required now. I'll drop it from the next patch 
series.


Thanks,
Vidya Sagar


Thierry


Re: [PATCH V4 1/6] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-12-03 Thread Vidya Sagar





-Original Message-
From: Thierry Reding 
Sent: Thursday, November 26, 2020 5:03 PM
To: Vidya Sagar 
Cc: lorenzo.pieral...@arm.com; robh...@kernel.org; bhelg...@google.com;
Jonathan Hunter ; amanharitsh...@gmail.com;
dinghao@zju.edu.cn; k...@linux.com; linux-...@vger.kernel.org; linux-
te...@vger.kernel.org; linux-kernel@vger.kernel.org; Krishna Thota
; Manikanta Maddireddy ;
sagar...@gmail.com
Subject: Re: [PATCH V4 1/6] PCI: tegra: Fix ASPM-L1SS advertisement disable
code

On Mon, Nov 09, 2020 at 10:49:32PM +0530, Vidya Sagar wrote:
> If the absence of CLKREQ# signal is indicated by the absence of
> "supports-clkreq" in the device-tree node, current driver is disabling
> the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1
> Sub-States offset is correctly initialized. Since default value of the
> ASPM-L1SS offset is zero, this is causing the Vendor-ID wrongly
> programmed to 0x10d2 instead of Nvidia's 0x10de thereby the quirks
> applicable for Tegra194 are not being applied. This patch fixes this
> issue by refactoring the code that disables the ASPM-L1SS advertisement.
>
> Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
> Signed-off-by: Vidya Sagar 
> ---
> V4:
> * None
>
> V3:
> * None
>
> V2:
> * None
>
>  drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
>  1 file changed, 6 insertions(+), 6 deletions(-)

Looks like this no longer applies cleanly after that other fix that you sent 
earlier.
But looking more closely, that's because that other fix already incorporates an
equivalent change, so I think this can be dropped from this series.
Yes. This is no longer applies cleanly and I'll fix it in the next 
series, but, the current patch is still required.
The other change I pushed is taking care of getting a valid 'dbi' 
address before accessing the dbi region, but, this current change would 
make sure that 'pcie->cfg_link_cap_l1sub' would have a valid value 
before calling disable_aspm_l1/2() APIs.


Thanks,
Vidya Sagar


Thierry


Re: [PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-12-03 Thread Vidya Sagar




On 11/25/2020 2:32 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Tue, Nov 24, 2020 at 03:50:01PM +0530, Vidya Sagar wrote:

Hi Bjorn,
Please let me know if this patch needs any further modifications


I'm fine with it, but of course Lorenzo will take care of it.

Thanks Bjorn.

Hi Lorenzo,
Please let me know if you have any comments for this patch.

Thanks,
Vidya Sagar




On 11/12/2020 10:32 PM, Vidya Sagar wrote:

External email: Use caution opening links or attachments


On 11/12/2020 3:59 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Wed, Nov 11, 2020 at 10:21:46PM +0530, Vidya Sagar wrote:



On 11/11/2020 9:57 PM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 11/11/20, 7:12 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in
one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue
with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

drivers/pci/controller/dwc/pcie-designware.c | 52
++--
drivers/pci/controller/dwc/pcie-designware.h |  1 +
2 files changed, 49 insertions(+), 4 deletions(-)

diff --git
a/drivers/pci/controller/dwc/pcie-designware.c
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void
dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index,
u32 reg,
 dw_pcie_writel_atu(pci, offset + reg, val);
}

+static inline u32 dw_pcie_enable_ecrc(u32 val)


What is the reason to use inline here?


Actually, I wanted to move the programming part inside the
respective APIs
but then I wanted to give some details as well in comments so to avoid
duplication, I came up with this function. But, I'm making it inline for
better code optimization by compiler.


I don't really care either way, but I'd be surprised if the compiler
didn't inline this all by itself even without the explicit "inline".

I just checked it and you are right that compiler is indeed inlining it
without explicitly mentioning 'inline'.
I hope it is ok to leave it that way.




+{
+ /*
+  * DesignWare core version 4.90A has this strange design issue
+  * where the 'TD' bit in the Control register-1 of
the ATU outbound
+  * region acts like an override for the ECRC
setting i.e. the presence
+  * of TLP Digest(ECRC) in the outgoing TLPs is
solely determined by
+  * this bit. This is contrary to the PCIe spec
which says that the
+  * enablement of the ECRC is solely determined by
the AER registers.
+  *
+  * Because of this, even when the ECRC is enabled through AER
+  * registers, the transactions going through ATU
won't have TLP Digest
+  * as there is no way the AER sub-system could
program the TD bit which
+  * is specific to DesignWare core.
+  *
+  * The best way to handle this scenario is to program the TD bit
+  * always. It affects only the traffic from root
port to downstream
+  * devices.
+  *
+  * At this point,
+  * When ECRC is enabled in AER registers,
everything works normally
+  * When ECRC is NOT enabled in AER registers, then,
+  * on Root Port:- TLP Digest (DWord size) gets
appended to each packet
+  *even through it is not required.
Since downstream
+  *TLPs are mostly for
configuration accesses and BAR
+  *accesses, they are not in
critical path and won't
+  *have much negative effect on the performance.
+  * on End Point:- TLP Digest is received for
some/all the packets coming
+  *from the root port. TLP Digest
is ignored because,
+  *as per the PCIe Spec r5.0 v1.0 section 2.2.3
+  *"TLP Digest Rules", when an
endpoint receives TLP
+  *Digest when its ECRC check
functionality is disabled
+  *in AER registers, received TLP
Digest is just ignored.
+  * Since there is no issue or error reported
either side, best way to
+  * handle the scenario is to program TD bit by default.
+  */
+
+ return val | PCIE_ATU_TD;
+}


Re: [PATCH] PCI: dwc: Set 32-bit DMA mask for MSI target address allocation

2020-12-02 Thread Vidya Sagar

Hi,
Could you please review this patch in the context of the following patch?
http://patchwork.ozlabs.org/project/linux-pci/patch/20201124105035.24573-1-vid...@nvidia.com/

Thanks,
Vidya Sagar

On 11/17/2020 10:23 PM, Vidya Sagar wrote:

Set DMA mask to 32-bit while allocating the MSI target address so that
the address is usable for both 32-bit and 64-bit MSI capable devices.
Throw a warning if it fails to set the mask to 32-bit to alert that
devices that are only 32-bit MSI capable may not work properly.

Signed-off-by: Vidya Sagar 
---
Given the other patch that I've pushed to the MSI sub-system
http://patchwork.ozlabs.org/project/linux-pci/patch/20201117145728.4516-1-vid...@nvidia.com/
which is going to catch any mismatch between MSI capability (32-bit) of the
device and system's inability to allocate the required MSI target address,
I'm not sure how much sense is this patch going to be make. But, I can
certainly say that if the memory allocation mechanism gives the addresses
from 64-bit pool by default, this patch at least makes sure that MSI target
address is allocated from 32-bit pool.

  drivers/pci/controller/dwc/pcie-designware-host.c | 8 
  1 file changed, 8 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index 44c2a6572199..e6a230eddf66 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -388,6 +388,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
dw_chained_msi_isr,
pp);
  
+			ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32));

+   if (!ret) {
+   dev_warn(pci->dev,
+"Failed to set DMA mask to 32-bit. "
+"Devices with only 32-bit MSI support"
+" may not work properly\n");
+   }
+
pp->msi_data = dma_map_single_attrs(pci->dev, 
>msi_msg,
  sizeof(pp->msi_msg),
  DMA_FROM_DEVICE,



Re: [PATCH V2] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-12-02 Thread Vidya Sagar

Hi Bjorn,
Do you have any further comments for this patch?

Thanks,
Vidya Sagar

On 11/24/2020 4:20 PM, Vidya Sagar wrote:

There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register. Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.

Signed-off-by: Vidya Sagar 
---
V2:
* Addressed Bjorn's comment and changed the error message

  drivers/pci/msi.c | 11 +++
  1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..8de5ba6b4a59 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
entry->msi_attrib.multi_cap  = (control & PCI_MSI_FLAGS_QMASK) >> 1;
entry->msi_attrib.multiple   = ilog2(__roundup_pow_of_two(nvec));
  
-	if (control & PCI_MSI_FLAGS_64BIT)

+   if (control & PCI_MSI_FLAGS_64BIT) {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
-   else
+   } else {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+   dev->no_64bit_msi = 1;
+   }
  
  	/* Save the initial mask status */

if (entry->msi_attrib.maskbit)
@@ -602,8 +604,9 @@ static int msi_verify_entries(struct pci_dev *dev)
for_each_pci_msi_entry(entry, dev) {
if (!dev->no_64bit_msi || !entry->msg.address_hi)
continue;
-   pci_err(dev, "Device has broken 64-bit MSI but arch"
-   " tried to assign one above 4G\n");
+   pci_err(dev, "Device has either broken 64-bit MSI or "
+   "only 32-bit MSI support but "
+   "arch tried to assign one above 4G\n");
return -EIO;
}
return 0;



Re: [PATCH V4 0/6] Enhancements to Tegra194 PCIe driver

2020-11-25 Thread Vidya Sagar





-Original Message-
From: Thierry Reding 
Sent: Wednesday, November 25, 2020 11:27 PM
To: Vidya Sagar 
Cc: lorenzo.pieral...@arm.com; robh...@kernel.org; bhelg...@google.com;
Jonathan Hunter ; amanharitsh...@gmail.com;
dinghao@zju.edu.cn; k...@linux.com; linux-...@vger.kernel.org; linux-
te...@vger.kernel.org; linux-kernel@vger.kernel.org; Krishna Thota
; Manikanta Maddireddy ;
sagar...@gmail.com
Subject: Re: [PATCH V4 0/6] Enhancements to Tegra194 PCIe driver

On Mon, Nov 09, 2020 at 10:49:31PM +0530, Vidya Sagar wrote:
> This series of patches do some enhancements and some bug fixes to the
> Tegra194 PCIe platform driver like
> - Fix Vendor-ID corruption
> - Map DBI space correctly
> - Update DWC IP version
> - Continue with uninitialization sequence even if parts fail
> - Check return value of tegra_pcie_init_controller()
>
> V4:
> * Added a new patch to address link-up issues with some of the cards
>
> V3:
> * Addressed Bjorn's review comments
> * Split earlier patch-4 into two
>   - Continue with the uninitialization sequence even if some parts fail
>   - Check return value of tegra_pcie_init_controller() and exit
> accordingly
>
> V2:
> * Addressed Rob's comments. Changed 'Strongly Ordered' to 'nGnRnE'
>
> Vidya Sagar (6):
>   PCI: tegra: Fix ASPM-L1SS advertisement disable code
>   PCI: tegra: Map configuration space as nGnRnE
>   PCI: tegra: Set DesignWare IP version
>   PCI: tegra: Continue unconfig sequence even if parts fail
>   PCI: tegra: Check return value of tegra_pcie_init_controller()
>   PCI: tegra: Disable LTSSM during L2 entry
>
>  drivers/pci/controller/dwc/pcie-tegra194.c | 78
> +++---
>  1 file changed, 39 insertions(+), 39 deletions(-)

I was going to test this series, but then I noticed that PCI is causing a crash 
on
linux-next (as of fairly recently).

I root caused the crash issue to the following commit
a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource 
setup into common code")


I also pushed the following two patches to fix this issue for review

http://patchwork.ozlabs.org/project/linux-pci/patch/20201125192234.2270-1-vid...@nvidia.com/
http://patchwork.ozlabs.org/project/linux-pci/patch/20201125192554.5401-1-vid...@nvidia.com/



So I tried applying this on top of v5.10-rc1, but
that gives me the following:

[3.595161] ahci 0001:01:00.0: version 3.0
[3.595726] ahci 0001:01:00.0: SSS flag set, parallel bus scan 
disabled
[4.609923] ahci 0001:01:00.0: controller reset failed (0x)
[4.610343] ahci: probe of 0001:01:00.0 failed with error -5

So the device enumerates fine, but it's not able to reset the SATA controller.
That said, this seems to happen regardless of this patch series, so plain 
v5.10-rc1
also shows the above.
This was also a known issue and we need the following commit to make 
things work (FWIW, it is already accepted)

9fff3256f93d PCI: dwc: Restore ATU memory resource setup to use last entry

Otherwise, v5.10-rc3 can be used which has working state of PCIe on 
Tegra194.




Given the above, I think we should hold off on applying this series until we've
fixed PCI on linux-next and made sure that SATA also works properly, otherwise
we don't have a known good baseline to test this against.

Thierry


[PATCH] PCI: tegra: Read "dbi" base address to program in application logic

2020-11-25 Thread Vidya Sagar
PCIe controller in Tegra194 requires the "dbi" region base address to be
programmed in one of the application logic registers to enable CPU access
to the "dbi" region. But, commit a0fd361db8e5 ("PCI: dwc: Move "dbi",
"dbi2", and "addr_space" resource setup into common code") moved the code
that reads the whereabouts of "dbi" region to the common code causing the
existing code in pcie-tegra194.c file to program NULL in the application
logic registers. This is causing null pointer dereference when the "dbi"
registers are accessed. This issue is fixed by explicitly reading the
"dbi" base address from DT node.

Fixes: a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource 
setup into common code")
Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index fa54d9aaa430..ac2225175087 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1053,9 +1053,16 @@ static int tegra_pcie_enable_phy(struct tegra_pcie_dw 
*pcie)
 
 static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
 {
+   struct platform_device *pdev = to_platform_device(pcie->dev);
struct device_node *np = pcie->dev->of_node;
int ret;
 
+   pcie->dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 
"dbi");
+   if (!pcie->dbi_res) {
+   dev_err(pcie->dev, "Failed to find \"dbi\" region\n");
+   return -ENODEV;
+   }
+
ret = of_property_read_u32(np, "nvidia,aspm-cmrt-us", >aspm_cmrt);
if (ret < 0) {
dev_info(pcie->dev, "Failed to read ASPM T_cmrt: %d\n", ret);
-- 
2.17.1



[PATCH] PCI: tegra: Move "dbi" accesses to post common DWC initialization

2020-11-25 Thread Vidya Sagar
commit a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space"
resource setup into common code") moved the code that sets up dbi_base
to DWC common code thereby creating a requirement to not access the "dbi"
region before calling common DWC initialization code. But, Tegra194
already had some code that programs some of the "dbi" registers resulting
in system crash. This patch addresses that issue by refactoring the code
to have accesses to the "dbi" region only after common DWC initialization.

Fixes: a0fd361db8e5 ("PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource 
setup into common code")
Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index ac2225175087..648e731bccfa 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -859,6 +859,16 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val;
 
+   if (!pcie->pcie_cap_base)
+   pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
+ PCI_CAP_ID_EXP);
+
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, PCI_IO_BASE);
val &= ~(IO_BASE_IO_DECODE | IO_BASE_IO_DECODE_BIT8);
dw_pcie_writel_dbi(pci, PCI_IO_BASE, val);
@@ -1389,15 +1399,6 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
 
reset_control_deassert(pcie->core_rst);
 
-   pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
- PCI_CAP_ID_EXP);
-
-   /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
return ret;
 
 fail_phy:
-- 
2.17.1



[PATCH V2] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-11-24 Thread Vidya Sagar
There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register. Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.

Signed-off-by: Vidya Sagar 
---
V2:
* Addressed Bjorn's comment and changed the error message

 drivers/pci/msi.c | 11 +++
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..8de5ba6b4a59 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
entry->msi_attrib.multiple  = ilog2(__roundup_pow_of_two(nvec));
 
-   if (control & PCI_MSI_FLAGS_64BIT)
+   if (control & PCI_MSI_FLAGS_64BIT) {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
-   else
+   } else {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+   dev->no_64bit_msi = 1;
+   }
 
/* Save the initial mask status */
if (entry->msi_attrib.maskbit)
@@ -602,8 +604,9 @@ static int msi_verify_entries(struct pci_dev *dev)
for_each_pci_msi_entry(entry, dev) {
if (!dev->no_64bit_msi || !entry->msg.address_hi)
continue;
-   pci_err(dev, "Device has broken 64-bit MSI but arch"
-   " tried to assign one above 4G\n");
+   pci_err(dev, "Device has either broken 64-bit MSI or "
+   "only 32-bit MSI support but "
+   "arch tried to assign one above 4G\n");
return -EIO;
}
return 0;
-- 
2.17.1



Re: [PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-11-24 Thread Vidya Sagar

Hi Bjorn,
Please let me know if this patch needs any further modifications

Thanks,
Vidya Sagar

On 11/12/2020 10:32 PM, Vidya Sagar wrote:

External email: Use caution opening links or attachments


On 11/12/2020 3:59 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Wed, Nov 11, 2020 at 10:21:46PM +0530, Vidya Sagar wrote:



On 11/11/2020 9:57 PM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 11/11/20, 7:12 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in one of the 
control

registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with 
DesignWare

IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

   drivers/pci/controller/dwc/pcie-designware.c | 52 
++--

   drivers/pci/controller/dwc/pcie-designware.h |  1 +
   2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c

index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void dw_pcie_writel_ob_unroll(struct 
dw_pcie *pci, u32 index, u32 reg,

    dw_pcie_writel_atu(pci, offset + reg, val);
   }

+static inline u32 dw_pcie_enable_ecrc(u32 val)


What is the reason to use inline here?


Actually, I wanted to move the programming part inside the respective 
APIs

but then I wanted to give some details as well in comments so to avoid
duplication, I came up with this function. But, I'm making it inline for
better code optimization by compiler.


I don't really care either way, but I'd be surprised if the compiler
didn't inline this all by itself even without the explicit "inline".

I just checked it and you are right that compiler is indeed inlining it
without explicitly mentioning 'inline'.
I hope it is ok to leave it that way.




+{
+ /*
+  * DesignWare core version 4.90A has this strange design issue
+  * where the 'TD' bit in the Control register-1 of the ATU 
outbound
+  * region acts like an override for the ECRC setting i.e. the 
presence
+  * of TLP Digest(ECRC) in the outgoing TLPs is solely 
determined by
+  * this bit. This is contrary to the PCIe spec which says 
that the
+  * enablement of the ECRC is solely determined by the AER 
registers.

+  *
+  * Because of this, even when the ECRC is enabled through AER
+  * registers, the transactions going through ATU won't have 
TLP Digest
+  * as there is no way the AER sub-system could program the TD 
bit which

+  * is specific to DesignWare core.
+  *
+  * The best way to handle this scenario is to program the TD bit
+  * always. It affects only the traffic from root port to 
downstream

+  * devices.
+  *
+  * At this point,
+  * When ECRC is enabled in AER registers, everything works 
normally

+  * When ECRC is NOT enabled in AER registers, then,
+  * on Root Port:- TLP Digest (DWord size) gets appended to 
each packet
+  *    even through it is not required. Since 
downstream
+  *    TLPs are mostly for configuration accesses 
and BAR
+  *    accesses, they are not in critical path and 
won't

+  *    have much negative effect on the performance.
+  * on End Point:- TLP Digest is received for some/all the 
packets coming
+  *    from the root port. TLP Digest is ignored 
because,

+  *    as per the PCIe Spec r5.0 v1.0 section 2.2.3
+  *    "TLP Digest Rules", when an endpoint 
receives TLP
+  *    Digest when its ECRC check functionality is 
disabled
+  *    in AER registers, received TLP Digest is 
just ignored.
+  * Since there is no issue or error reported either side, 
best way to

+  * handle the scenario is to program TD bit by default.
+  */
+
+ return val | PCIE_ATU_TD;
+}


Re: [PATCH] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-11-23 Thread Vidya Sagar




On 11/21/2020 3:00 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Tue, Nov 17, 2020 at 08:27:28PM +0530, Vidya Sagar wrote:

There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register.


I *think* you're saying these devices behave correctly per spec: they
don't support 64-bit MSI, and they don't advertise support for 64-bit
MSI.  Right?

Yes. That is what I intended to say.




Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.


And you want msi_verify_entries() to catch attempts by the arch code
to assign a 64-bit MSI address?

Yes.



That sounds OK, but the error message ("Device has broken 64-bit MSI")
is not appropriate if the device is actually *not* broken.
Ok. I didn't change the existing error message. I'll change it to cover 
both the scenarios i.e. either the device is broken or the device 
doesn't really support 64-bit MSI.





Signed-off-by: Vidya Sagar 
---
  drivers/pci/msi.c | 6 --
  1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..af49da28854e 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
   entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
   entry->msi_attrib.multiple  = ilog2(__roundup_pow_of_two(nvec));

- if (control & PCI_MSI_FLAGS_64BIT)
+ if (control & PCI_MSI_FLAGS_64BIT) {
   entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
- else
+ } else {
   entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+ dev->no_64bit_msi = 1;
+ }

   /* Save the initial mask status */
   if (entry->msi_attrib.maskbit)
--
2.17.1



[PATCH V2 2/2] PCI: dwc: Add support to program ATU for >4GB memory

2020-11-18 Thread Vidya Sagar
Add support to program the ATU to enable translations for >4GB sizes of
the prefetchable memory apertures.

Tested-by: Thierry Reding 
Tested-by: Jon Hunter 
Signed-off-by: Vidya Sagar 
Reviewed-by: Rob Herring 
Acked-by: Jingoo 
---
V2:
* Added 'Tested-by', 'Reviewed-by' and 'Acked-by'

 drivers/pci/controller/dwc/pcie-designware.c | 12 +++-
 drivers/pci/controller/dwc/pcie-designware.h |  3 ++-
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..b5e438b70cd5 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
-u32 size)
+u64 size)
 {
u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
@@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-type | PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   val = upper_32_bits(size - 1) ?
+   val | PCIE_ATU_INCREASE_REGION_SIZE : val;
+   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 PCIE_ATU_ENABLE);
 
@@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
 
 static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr,
-   u64 pci_addr, u32 size)
+   u64 pci_addr, u64 size)
 {
u32 retries, val;
 
@@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
 }
 
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
-  u64 cpu_addr, u64 pci_addr, u32 size)
+  u64 cpu_addr, u64 pci_addr, u64 size)
 {
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index ed19c34dd0fe..f9a20ce9ab9a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -81,6 +81,7 @@
 #define PCIE_ATU_REGION_INBOUNDBIT(31)
 #define PCIE_ATU_REGION_OUTBOUND   0
 #define PCIE_ATU_CR1   0x904
+#define PCIE_ATU_INCREASE_REGION_SIZE  BIT(13)
 #define PCIE_ATU_TYPE_MEM  0x0
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
@@ -293,7 +294,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
   int type, u64 cpu_addr, u64 pci_addr,
-  u32 size);
+  u64 size);
 void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
  int type, u64 cpu_addr, u64 pci_addr,
  u32 size);
-- 
2.17.1



[PATCH V2 1/2] PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit

2020-11-18 Thread Vidya Sagar
As per PCIe spec r5.0, sec 7.5.1.3.8 only 32-bit BAR registers are defined
for non-prefetchable memory and hence a warning should be reported when
the size of them go beyond 32-bits.

Tested-by: Thierry Reding 
Tested-by: Jon Hunter 
Signed-off-by: Vidya Sagar 
Reviewed-by: Rob Herring 
---
V2:
* Added 'Tested-by' and 'Reviewed-by'

 drivers/pci/of.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index ac24cd5439a9..5ea472ae22ac 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -556,6 +556,11 @@ static int pci_parse_request_of_pci_ranges(struct device 
*dev,
break;
case IORESOURCE_MEM:
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+
+   if (!(res->flags & IORESOURCE_PREFETCH))
+   if (upper_32_bits(resource_size(res)))
+   dev_warn(dev, "Memory resource size 
exceeds max for 32 bits\n");
+
break;
}
}
-- 
2.17.1



[PATCH V2 0/2] Add support to handle prefetchable memory

2020-11-18 Thread Vidya Sagar
This patch series adds support for configuring the DesignWare IP's ATU
region for prefetchable memory translations.
It first starts by flagging a warning if the size of non-prefetchable
aperture goes beyond 32-bit as PCIe spec doesn't allow it.
And then adds required support for programming the ATU to handle higher
(i.e. >4GB) sizes.

V2:
* Dropped third patch from the series as Rob's patch
  (commit: 9fff3256f93d PCI: dwc: Restore ATU memory resource setup to use last 
entry)
  is already accepted
* Rebased first two patches on top of Rob's latest patch
  
http://patchwork.ozlabs.org/project/linux-pci/patch/20201026181652.418729-1-r...@kernel.org/

Vidya Sagar (2):
  PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit
  PCI: dwc: Add support to program ATU for >4GB memory

 drivers/pci/controller/dwc/pcie-designware.c | 12 +++-
 drivers/pci/controller/dwc/pcie-designware.h |  3 ++-
 drivers/pci/of.c |  5 +
 3 files changed, 14 insertions(+), 6 deletions(-)

-- 
2.17.1



Re: [PATCH 0/3] Add support to handle prefetchable memoryg

2020-11-17 Thread Vidya Sagar




On 11/17/2020 5:40 PM, Lorenzo Pieralisi wrote:

External email: Use caution opening links or attachments


On Tue, Nov 17, 2020 at 10:08:35AM +0530, Vidya Sagar wrote:

Hi Lorenzo & Bjorn,
Sorry to bother you.
Could you please take a look at the patches-1 & 2 from this series?


IIUC we should:

(1) apply 
https://patchwork.kernel.org/project/linux-pci/patch/20201026181652.418729-1-r...@kernel.org
(2) apply [1,2] from this series

For (2), are they rebased against v5.10-rc3 with (1) applied ? I need to
check but I will probably have to use v5.10-rc3 as baseline owing to
commit:

9fff3256f93d

(1) depends on it.

Lorenzo
My patches [1,2] from this series apply cleanly on v5.10-rc3. But with 
(1) applied first, there is a trivial rebase required. Let me know if 
you want me to send the trivial rebased version (of patch-2 particularly).


Thanks,
Vidya Sagar



Thanks,
Vidya Sagar

On 11/4/2020 1:16 PM, Vidya Sagar wrote:

External email: Use caution opening links or attachments


Lorenzo / Bjorn,
Could you please review patches-1 & 2 in this series?
For the third patch, we already went with Rob's patch @
http://patchwork.ozlabs.org/project/linux-pci/patch/20201026154852.221483-1-r...@kernel.org/


Thanks,
Vidya Sagar

On 10/26/2020 6:02 PM, Thierry Reding wrote:

On Sat, Oct 24, 2020 at 04:03:41AM +, Jingoo Han wrote:

On 10/23/20, 3:57 PM, Vidya Sagar wrote:


This patch series adds support for configuring the DesignWare IP's ATU
region for prefetchable memory translations.
It first starts by flagging a warning if the size of non-prefetchable
aperture goes beyond 32-bit as PCIe spec doesn't allow it.
And then adds required support for programming the ATU to handle higher
(i.e. >4GB) sizes and then finally adds support for differentiating
between prefetchable and non-prefetchable regions and
configuring one of
the ATU regions for prefetchable memory translations purpose.

Vidya Sagar (3):
PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit
PCI: dwc: Add support to program ATU for >4GB memory aperture sizes
PCI: dwc: Add support to handle prefetchable memory mapping


For 2nd & 3rd,
Acked-by: Jingoo 
But, I still want someone to ack 1st patch, not me.

To Vidya,
If possible, can you ask your coworker to give 'Tested-by'? It
will be very helpful.
Thank you.


On next-20201026 (but also going back quite a while) I'm seeing this
during boot on Jetson AGX Xavier (Tegra194):

[    3.493382] ahci 0001:01:00.0: version 3.0
[    3.493889] ahci 0001:01:00.0: SSS flag set, parallel bus scan
disabled
[    4.497706] ahci 0001:01:00.0: controller reset failed (0x)
[    4.498114] ahci: probe of 0001:01:00.0 failed with error -5

After applying this series, AHCI over PCI is back to normal:

[    3.543230] ahci 0001:01:00.0: AHCI 0001. 32 slots 1 ports 6
Gbps 0x1 impl SATA mode
[    3.550841] ahci 0001:01:00.0: flags: 64bit ncq sntf led only pmp
fbs pio slum part sxs
[    3.559747] scsi host0: ahci
[    3.561998] ata1: SATA max UDMA/133 abar m512@0x123001 port
0x1230010100 irq 63

So for the series:

Tested-by: Thierry Reding 



[PATCH] PCI: dwc: Set 32-bit DMA mask for MSI target address allocation

2020-11-17 Thread Vidya Sagar
Set DMA mask to 32-bit while allocating the MSI target address so that
the address is usable for both 32-bit and 64-bit MSI capable devices.
Throw a warning if it fails to set the mask to 32-bit to alert that
devices that are only 32-bit MSI capable may not work properly.

Signed-off-by: Vidya Sagar 
---
Given the other patch that I've pushed to the MSI sub-system
http://patchwork.ozlabs.org/project/linux-pci/patch/20201117145728.4516-1-vid...@nvidia.com/
which is going to catch any mismatch between MSI capability (32-bit) of the
device and system's inability to allocate the required MSI target address,
I'm not sure how much sense is this patch going to be make. But, I can
certainly say that if the memory allocation mechanism gives the addresses
from 64-bit pool by default, this patch at least makes sure that MSI target
address is allocated from 32-bit pool.

 drivers/pci/controller/dwc/pcie-designware-host.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index 44c2a6572199..e6a230eddf66 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -388,6 +388,14 @@ int dw_pcie_host_init(struct pcie_port *pp)
dw_chained_msi_isr,
pp);
 
+   ret = dma_set_mask(pci->dev, DMA_BIT_MASK(32));
+   if (!ret) {
+   dev_warn(pci->dev,
+"Failed to set DMA mask to 32-bit. "
+"Devices with only 32-bit MSI support"
+" may not work properly\n");
+   }
+
pp->msi_data = dma_map_single_attrs(pci->dev, 
>msi_msg,
  sizeof(pp->msi_msg),
  DMA_FROM_DEVICE,
-- 
2.17.1



[PATCH] PCI/MSI: Set device flag indicating only 32-bit MSI support

2020-11-17 Thread Vidya Sagar
There are devices (Ex:- Marvell SATA controller) that don't support
64-bit MSIs and the same is advertised through their MSI capability
register. Set no_64bit_msi flag explicitly for such devices in the
MSI setup code so that the msi_verify_entries() API would catch
if the MSI arch code tries to use 64-bit MSI.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/msi.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index d52d118979a6..af49da28854e 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -581,10 +581,12 @@ msi_setup_entry(struct pci_dev *dev, int nvec, struct 
irq_affinity *affd)
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
entry->msi_attrib.multiple  = ilog2(__roundup_pow_of_two(nvec));
 
-   if (control & PCI_MSI_FLAGS_64BIT)
+   if (control & PCI_MSI_FLAGS_64BIT) {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
-   else
+   } else {
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_32;
+   dev->no_64bit_msi = 1;
+   }
 
/* Save the initial mask status */
if (entry->msi_attrib.maskbit)
-- 
2.17.1



Re: [PATCH 0/3] Add support to handle prefetchable memory

2020-11-16 Thread Vidya Sagar

Hi Lorenzo & Bjorn,
Sorry to bother you.
Could you please take a look at the patches-1 & 2 from this series?

Thanks,
Vidya Sagar

On 11/4/2020 1:16 PM, Vidya Sagar wrote:

External email: Use caution opening links or attachments


Lorenzo / Bjorn,
Could you please review patches-1 & 2 in this series?
For the third patch, we already went with Rob's patch @
http://patchwork.ozlabs.org/project/linux-pci/patch/20201026154852.221483-1-r...@kernel.org/ 



Thanks,
Vidya Sagar

On 10/26/2020 6:02 PM, Thierry Reding wrote:

On Sat, Oct 24, 2020 at 04:03:41AM +, Jingoo Han wrote:

On 10/23/20, 3:57 PM, Vidya Sagar wrote:


This patch series adds support for configuring the DesignWare IP's ATU
region for prefetchable memory translations.
It first starts by flagging a warning if the size of non-prefetchable
aperture goes beyond 32-bit as PCIe spec doesn't allow it.
And then adds required support for programming the ATU to handle higher
(i.e. >4GB) sizes and then finally adds support for differentiating
between prefetchable and non-prefetchable regions and configuring 
one of

the ATU regions for prefetchable memory translations purpose.

Vidya Sagar (3):
   PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit
   PCI: dwc: Add support to program ATU for >4GB memory aperture sizes
   PCI: dwc: Add support to handle prefetchable memory mapping


For 2nd & 3rd,
Acked-by: Jingoo 
But, I still want someone to ack 1st patch, not me.

To Vidya,
If possible, can you ask your coworker to give 'Tested-by'? It will 
be very helpful.

Thank you.


On next-20201026 (but also going back quite a while) I'm seeing this
during boot on Jetson AGX Xavier (Tegra194):

[    3.493382] ahci 0001:01:00.0: version 3.0
[    3.493889] ahci 0001:01:00.0: SSS flag set, parallel bus scan 
disabled

[    4.497706] ahci 0001:01:00.0: controller reset failed (0x)
[    4.498114] ahci: probe of 0001:01:00.0 failed with error -5

After applying this series, AHCI over PCI is back to normal:

[    3.543230] ahci 0001:01:00.0: AHCI 0001. 32 slots 1 ports 6 
Gbps 0x1 impl SATA mode
[    3.550841] ahci 0001:01:00.0: flags: 64bit ncq sntf led only pmp 
fbs pio slum part sxs

[    3.559747] scsi host0: ahci
[    3.561998] ata1: SATA max UDMA/133 abar m512@0x123001 port 
0x1230010100 irq 63


So for the series:

Tested-by: Thierry Reding 



Re: [PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-11-12 Thread Vidya Sagar




On 11/12/2020 3:59 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Wed, Nov 11, 2020 at 10:21:46PM +0530, Vidya Sagar wrote:



On 11/11/2020 9:57 PM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 11/11/20, 7:12 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

   drivers/pci/controller/dwc/pcie-designware.c | 52 ++--
   drivers/pci/controller/dwc/pcie-designware.h |  1 +
   2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
dw_pcie_writel_atu(pci, offset + reg, val);
   }

+static inline u32 dw_pcie_enable_ecrc(u32 val)


What is the reason to use inline here?


Actually, I wanted to move the programming part inside the respective APIs
but then I wanted to give some details as well in comments so to avoid
duplication, I came up with this function. But, I'm making it inline for
better code optimization by compiler.


I don't really care either way, but I'd be surprised if the compiler
didn't inline this all by itself even without the explicit "inline".
I just checked it and you are right that compiler is indeed inlining it 
without explicitly mentioning 'inline'.

I hope it is ok to leave it that way.




+{
+ /*
+  * DesignWare core version 4.90A has this strange design issue
+  * where the 'TD' bit in the Control register-1 of the ATU outbound
+  * region acts like an override for the ECRC setting i.e. the presence
+  * of TLP Digest(ECRC) in the outgoing TLPs is solely determined by
+  * this bit. This is contrary to the PCIe spec which says that the
+  * enablement of the ECRC is solely determined by the AER registers.
+  *
+  * Because of this, even when the ECRC is enabled through AER
+  * registers, the transactions going through ATU won't have TLP Digest
+  * as there is no way the AER sub-system could program the TD bit which
+  * is specific to DesignWare core.
+  *
+  * The best way to handle this scenario is to program the TD bit
+  * always. It affects only the traffic from root port to downstream
+  * devices.
+  *
+  * At this point,
+  * When ECRC is enabled in AER registers, everything works normally
+  * When ECRC is NOT enabled in AER registers, then,
+  * on Root Port:- TLP Digest (DWord size) gets appended to each packet
+  *even through it is not required. Since downstream
+  *TLPs are mostly for configuration accesses and BAR
+  *accesses, they are not in critical path and won't
+  *have much negative effect on the performance.
+  * on End Point:- TLP Digest is received for some/all the packets coming
+  *from the root port. TLP Digest is ignored because,
+  *as per the PCIe Spec r5.0 v1.0 section 2.2.3
+  *"TLP Digest Rules", when an endpoint receives TLP
+  *Digest when its ECRC check functionality is disabled
+  *in AER registers, received TLP Digest is just ignored.
+  * Since there is no issue or error reported either side, best way to
+  * handle the scenario is to program TD bit by default.
+  */
+
+ return val | PCIE_ATU_TD;
+}


Re: [PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-11-11 Thread Vidya Sagar




On 11/11/2020 9:57 PM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 11/11/20, 7:12 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

  drivers/pci/controller/dwc/pcie-designware.c | 52 ++--
  drivers/pci/controller/dwc/pcie-designware.h |  1 +
  2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
   dw_pcie_writel_atu(pci, offset + reg, val);
  }

+static inline u32 dw_pcie_enable_ecrc(u32 val)


What is the reason to use inline here?
Actually, I wanted to move the programming part inside the respective 
APIs but then I wanted to give some details as well in comments so to 
avoid duplication, I came up with this function. But, I'm making it 
inline for better code optimization by compiler.





Best regards,
Jingoo Han


+{
+ /*
+  * DesignWare core version 4.90A has this strange design issue
+  * where the 'TD' bit in the Control register-1 of the ATU outbound
+  * region acts like an override for the ECRC setting i.e. the presence
+  * of TLP Digest(ECRC) in the outgoing TLPs is solely determined by
+  * this bit. This is contrary to the PCIe spec which says that the
+  * enablement of the ECRC is solely determined by the AER registers.
+  *
+  * Because of this, even when the ECRC is enabled through AER
+  * registers, the transactions going through ATU won't have TLP Digest
+  * as there is no way the AER sub-system could program the TD bit which
+  * is specific to DesignWare core.
+  *
+  * The best way to handle this scenario is to program the TD bit
+  * always. It affects only the traffic from root port to downstream
+  * devices.
+  *
+  * At this point,
+  * When ECRC is enabled in AER registers, everything works normally
+  * When ECRC is NOT enabled in AER registers, then,
+  * on Root Port:- TLP Digest (DWord size) gets appended to each packet
+  *even through it is not required. Since downstream
+  *TLPs are mostly for configuration accesses and BAR
+  *accesses, they are not in critical path and won't
+  *have much negative effect on the performance.
+  * on End Point:- TLP Digest is received for some/all the packets coming
+  *from the root port. TLP Digest is ignored because,
+  *as per the PCIe Spec r5.0 v1.0 section 2.2.3
+  *"TLP Digest Rules", when an endpoint receives TLP
+  *Digest when its ECRC check functionality is disabled
+  *in AER registers, received TLP Digest is just ignored.
+  * Since there is no issue or error reported either side, best way to
+  * handle the scenario is to program TD bit by default.
+  */
+
+ return val | PCIE_ATU_TD;
+}
+
  static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
int index, int type,
u64 cpu_addr, u64 pci_addr,
@@ -245,8 +285,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
lower_32_bits(pci_addr));
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-  type | PCIE_ATU_FUNC_NUM(func_no));
+ val = type | PCIE_ATU_FUNC_NUM(func_no);
+ if (pci->version == 0x490A)
+ val = dw_pcie_enable_ecrc(val);
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE);

@@ -292,8 +334,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
  lower_32_bits(pci_addr));
   dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
  upper_32_bits(pci_addr));
- dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-PCIE_ATU_FUNC_NUM(func_no));
+ val = type | PCIE_ATU_FUNC_NUM(func_no);
+ if (pci->version == 0x490A)
+ val = dw_pcie_enable_ecrc(val);
+ dw_pci

[PATCH V2] PCI: dwc: Add support to configure for ECRC

2020-11-11 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
Acked-by: Bjorn Helgaas 
---
V2:
* Addressed Bjorn's comments

 drivers/pci/controller/dwc/pcie-designware.c | 52 ++--
 drivers/pci/controller/dwc/pcie-designware.h |  1 +
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ec0d13ab6bad 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,46 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
+static inline u32 dw_pcie_enable_ecrc(u32 val)
+{
+   /*
+* DesignWare core version 4.90A has this strange design issue
+* where the 'TD' bit in the Control register-1 of the ATU outbound
+* region acts like an override for the ECRC setting i.e. the presence
+* of TLP Digest(ECRC) in the outgoing TLPs is solely determined by
+* this bit. This is contrary to the PCIe spec which says that the
+* enablement of the ECRC is solely determined by the AER registers.
+*
+* Because of this, even when the ECRC is enabled through AER
+* registers, the transactions going through ATU won't have TLP Digest
+* as there is no way the AER sub-system could program the TD bit which
+* is specific to DesignWare core.
+*
+* The best way to handle this scenario is to program the TD bit
+* always. It affects only the traffic from root port to downstream
+* devices.
+*
+* At this point,
+* When ECRC is enabled in AER registers, everything works normally
+* When ECRC is NOT enabled in AER registers, then,
+* on Root Port:- TLP Digest (DWord size) gets appended to each packet
+*even through it is not required. Since downstream
+*TLPs are mostly for configuration accesses and BAR
+*accesses, they are not in critical path and won't
+*have much negative effect on the performance.
+* on End Point:- TLP Digest is received for some/all the packets coming
+*from the root port. TLP Digest is ignored because,
+*as per the PCIe Spec r5.0 v1.0 section 2.2.3
+*"TLP Digest Rules", when an endpoint receives TLP
+*Digest when its ECRC check functionality is disabled
+*in AER registers, received TLP Digest is just ignored.
+* Since there is no issue or error reported either side, best way to
+* handle the scenario is to program TD bit by default.
+*/
+
+   return val | PCIE_ATU_TD;
+}
+
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
@@ -245,8 +285,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-type | PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
+   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 PCIE_ATU_ENABLE);
 
@@ -292,8 +334,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
+   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 9d2f511f13fa..285c0ae364ae 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -88,6 +

[PATCH] PCI: dwc: Add support to configure for ECRC

2020-11-09 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-designware.c | 50 ++--
 drivers/pci/controller/dwc/pcie-designware.h |  1 +
 2 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..ebdc37a58e94 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -225,6 +225,44 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
dw_pcie_writel_atu(pci, offset + reg, val);
 }
 
+static inline u32 dw_pcie_enable_ecrc(u32 val)
+{
+   /*
+* DesignWare core version 4.90A has this strange design issue
+* where the 'TD' bit in the Control register-1 of the ATU outbound
+* region acts like an override for the ECRC setting i.e. the presence
+* of TLP Digest(ECRC) in the outgoing TLPs is solely determined by
+* this bit. This is contrary to the PCIe spec which says that the
+* enablement of the ECRC is solely determined by the AER registers.
+* Because of this, even when the ECRC is enabled through AER
+* registers, the transactions going through ATU won't have TLP Digest
+* as there is no way the AER sub-system could program the TD bit which
+* is specific to DsignWare core.
+*The best way to handle this scenario is to program the TD bit
+* always. It affects only the traffic from root port to downstream
+* devices.
+* At this point,
+* When ECRC is enabled in AER registers, everything works
+* normally
+* When ECRC is NOT enabled in AER registers, then,
+* on Root Port:- TLP Digest (DWord size) gets appended to each packet
+*even through it is not required. Since downstream
+*TLPs are mostly for configuration accesses and BAR
+*accesses, they are not in critical path and won't
+*have much negative effect on the performance.
+* on End Point:- TLP Digest is received for some/all the packets coming
+*from the root port. TLP Digest is ignored because,
+*as per the PCIe Spec r5.0 v1.0 section 2.2.3 "TLP 
Digest Rules",
+*when an endpoint receives TLP Digest when its
+*ECRC check functionality is disabled in AER registers,
+*received TLP Digest is just ignored.
+* Since there is no issue or error reported either side, best way to
+* handle the scenario is to program TD bit by default.
+*/
+
+   return val | PCIE_ATU_TD;
+}
+
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
@@ -245,8 +283,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-type | PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
+   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 PCIE_ATU_ENABLE);
 
@@ -292,8 +332,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = dw_pcie_enable_ecrc(val);
+   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 9d2f511f13fa..285c0ae364ae 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -88,6 +88,7 @@
 #define PCIE_ATU_TYPE_IO   0x2
 #define PC

[PATCH V4 6/6] PCI: tegra: Disable LTSSM during L2 entry

2020-11-09 Thread Vidya Sagar
PCIe cards like Marvell SATA controller and some of the Samsung NVMe
drives don't support taking the link to L2 state. When the link doesn't
go to L2 state, Tegra194 requires the LTSSM to be disabled to allow PHY
to start the next link up process cleanly during suspend/resume sequence.
Failing to disable LTSSM results in the PCIe link not coming up in the
next resume cycle.

Signed-off-by: Vidya Sagar 
---
V4:
* New patch in this series

 drivers/pci/controller/dwc/pcie-tegra194.c | 16 +---
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 8c08998b9ce1..57ff0657bbe2 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1513,6 +1513,14 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
data &= ~APPL_PINMUX_PEX_RST;
appl_writel(pcie, data, APPL_PINMUX);
 
+   /*
+* Some cards do not go to detect state even after de-asserting
+* PERST#. So, de-assert LTSSM to bring link to detect state.
+*/
+   data = readl(pcie->appl_base + APPL_CTRL);
+   data &= ~APPL_CTRL_LTSSM_EN;
+   writel(data, pcie->appl_base + APPL_CTRL);
+
err = readl_poll_timeout_atomic(pcie->appl_base + APPL_DEBUG,
data,
((data &
@@ -1520,14 +1528,8 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
APPL_DEBUG_LTSSM_STATE_SHIFT) ==
LTSSM_STATE_PRE_DETECT,
1, LTSSM_TIMEOUT);
-   if (err) {
+   if (err)
dev_info(pcie->dev, "Link didn't go to detect state\n");
-   } else {
-   /* Disable LTSSM after link is in detect state */
-   data = appl_readl(pcie, APPL_CTRL);
-   data &= ~APPL_CTRL_LTSSM_EN;
-   appl_writel(pcie, data, APPL_CTRL);
-   }
}
/*
 * DBI registers may not be accessible after this as PLL-E would be
-- 
2.17.1



[PATCH V4 2/6] PCI: tegra: Map configuration space as nGnRnE

2020-11-09 Thread Vidya Sagar
As specified in the comment for pci_remap_cfgspace() define in
arch/arm64/include/asm/io.h file, PCIe configuration space should be
mapped as nGnRnE. Hence changing to dev_pci_remap_cfgspace() from
devm_ioremap_resource() for mapping DBI space as that is nothing but
the root port's own configuration space.

Signed-off-by: Vidya Sagar 
---
V4:
* None

V3:
* None

V2:
* Changed 'Strongly Ordered' to 'nGnRnE'

 drivers/pci/controller/dwc/pcie-tegra194.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index b172b1d49713..7a0c64436861 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2108,7 +2108,9 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
}
pcie->dbi_res = dbi_res;
 
-   pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
+   pci->dbi_base = devm_pci_remap_cfgspace(dev,
+   dbi_res->start,
+   resource_size(dbi_res));
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
 
-- 
2.17.1



[PATCH V4 4/6] PCI: tegra: Continue unconfig sequence even if parts fail

2020-11-09 Thread Vidya Sagar
Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.

Signed-off-by: Vidya Sagar 
---
V4:
* None

V3:
* Modified subject as per Bjorn's suggestion
* Removed tegra_pcie_init_controller()'s error checking part and pushed
  a separate patch for it

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 39 +-
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 253d91033bc3..9be10c8953df 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1422,43 +1422,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
int ret;
 
ret = reset_control_assert(pcie->core_rst);
-   if (ret) {
-   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-   ret);
-   return ret;
-   }
+   if (ret)
+   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", 
ret);
 
tegra_pcie_disable_phy(pcie);
 
ret = reset_control_assert(pcie->core_apb_rst);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-   return ret;
-   }
 
clk_disable_unprepare(pcie->core_clk);
 
ret = regulator_disable(pcie->pex_ctl_supply);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-   return ret;
-   }
 
tegra_pcie_disable_slot_regulators(pcie);
 
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
-   return ret;
-   }
-
-   return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1482,7 +1471,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1551,13 +1541,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(>pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
-
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -2238,8 +2227,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
   PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 
-   return __deinit_controller(pcie);
+   return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2267,7 +2257,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2305,7 +2296,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device 
*pdev)
disable_irq(pcie->pci.pp.msi_irq);
 
tegra_pcie_dw_pme_turnoff(pcie);
-   __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
-- 
2.17.1



[PATCH V4 5/6] PCI: tegra: Check return value of tegra_pcie_init_controller()

2020-11-09 Thread Vidya Sagar
The return value of tegra_pcie_init_controller() must be checked before
PCIe link up check and registering debugfs entries subsequently as it
doesn't make sense to do these when the controller initialization itself
has failed.

Signed-off-by: Vidya Sagar 
---
V4:
* None

V3:
* New patch in this series

 drivers/pci/controller/dwc/pcie-tegra194.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 9be10c8953df..8c08998b9ce1 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1579,7 +1579,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
goto fail_pm_get_sync;
}
 
-   tegra_pcie_init_controller(pcie);
+   ret = tegra_pcie_init_controller(pcie);
+   if (ret < 0) {
+   dev_err(dev, "Failed to initialize controller: %d\n", ret);
+   goto fail_pm_get_sync;
+   }
 
pcie->link_state = tegra_pcie_dw_link_up(>pci);
if (!pcie->link_state) {
-- 
2.17.1



[PATCH V4 1/6] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-11-09 Thread Vidya Sagar
If the absence of CLKREQ# signal is indicated by the absence of
"supports-clkreq" in the device-tree node, current driver is disabling
the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States
offset is correctly initialized. Since default value of the ASPM-L1SS
offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2
instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are
not being applied. This patch fixes this issue by refactoring the
code that disables the ASPM-L1SS advertisement.

Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar 
---
V4:
* None

V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index aa511ec0d800..b172b1d49713 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -896,6 +896,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
init_host_aspm(pcie);
 
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@@ -1400,12 +1406,6 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
  PCI_CAP_ID_EXP);
 
-   /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
return ret;
 
 fail_phy:
-- 
2.17.1



[PATCH V4 3/6] PCI: tegra: Set DesignWare IP version

2020-11-09 Thread Vidya Sagar
Set the DesignWare IP version for Tegra194 to 0x490A. This would be used
by the DesigWare sub-system to do any version specific configuration
(Ex:- TD bit programming for ECRC).

Signed-off-by: Vidya Sagar 
---
V4:
* None

V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 7a0c64436861..253d91033bc3 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2011,6 +2011,7 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
pci->ops = _dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
+   pci->version = 0x490A;
 
pp = >pp;
pcie->dev = >dev;
-- 
2.17.1



[PATCH V4 0/6] Enhancements to Tegra194 PCIe driver

2020-11-09 Thread Vidya Sagar
This series of patches do some enhancements and some bug fixes to the
Tegra194 PCIe platform driver like
- Fix Vendor-ID corruption
- Map DBI space correctly
- Update DWC IP version
- Continue with uninitialization sequence even if parts fail
- Check return value of tegra_pcie_init_controller()

V4:
* Added a new patch to address link-up issues with some of the cards

V3:
* Addressed Bjorn's review comments
* Split earlier patch-4 into two
  - Continue with the uninitialization sequence even if some parts fail
  - Check return value of tegra_pcie_init_controller() and exit accordingly

V2:
* Addressed Rob's comments. Changed 'Strongly Ordered' to 'nGnRnE'

Vidya Sagar (6):
  PCI: tegra: Fix ASPM-L1SS advertisement disable code
  PCI: tegra: Map configuration space as nGnRnE
  PCI: tegra: Set DesignWare IP version
  PCI: tegra: Continue unconfig sequence even if parts fail
  PCI: tegra: Check return value of tegra_pcie_init_controller()
  PCI: tegra: Disable LTSSM during L2 entry

 drivers/pci/controller/dwc/pcie-tegra194.c | 78 +++---
 1 file changed, 39 insertions(+), 39 deletions(-)

-- 
2.17.1



Re: [PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-11-04 Thread Vidya Sagar




On 11/4/2020 9:52 PM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Wed, Nov 04, 2020 at 05:13:07PM +0530, Vidya Sagar wrote:

On 11/4/2020 2:37 AM, Bjorn Helgaas wrote:

On Tue, Nov 03, 2020 at 08:57:01AM +0530, Vidya Sagar wrote:

On 11/3/2020 4:32 AM, Bjorn Helgaas wrote:

On Thu, Oct 29, 2020 at 11:09:59AM +0530, Vidya Sagar wrote:

DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.


I guess this is a hardware defect, right?

Yes. This is common across all DWC implementations (version 4.90 precisely)


How much of a problem would it be if we instead added a "no_ecrc"
quirk for this hardware so we never enabled ECRC?

Well, on Tegra for some of the high fidelity use cases, ECRC is required to
be turned on and if it can be done safely with these patches, why shouldn't
we not enable ECRC at all?


IIUC, the current Linux support of ECRC is a single choice at
boot-time: by default ECRC is not enabled, but if you boot with
"pci=ecrc=on", we turn on ECRC for every device.

That seems like the minimal support, but I think the spec allows ECRC
to be enabled selectively, on individual devices.  I can imagine a
sysfs knob that would allow us to enable/disable ECRC per-device at
run-time.

If we had such a sysfs knob, it would be pretty ugly and maybe
impractical to work around this hardware issue.  So I'm a little bit
hesitant to add functionality that might have to be removed in the
future.


Agree with this. But since it is a boot-time choice at this point, I think
we can still go ahead with this approach to have a working ECRC mechanism
right? I don't see any sysfs knob for AER controlling at this point.


I don't want to do anything that will prevent us from adding
per-device ECRC control in the future.

My concern is that if we add a run-time sysfs knob in the future, the
user experience on this hardware will be poor because there's no
convenient path to twiddle the PCIE_ATU_TD bit when the generic code
changes the AER Control bit.


Agree.
Can we add it to the documentation that run time changing of ECRC settings
are not supported on this (i.e. Tegra194) platform (or for that matter on
any SoC with PCIe based on DesignWare core version 4.90A). By 'not
supported', I meant that the ECRC digest part may not work but the normal
functionality will continue to work without reporting any AER errors. I
tried to emulate the following scenarios on Tegra194 silicon and here are my
observations.
FWIW, I'm referring to the PCIe spec Rev 5.0 Ver 1.0 (22 May 2019)


What is the failure mode in these scenarios:

- User boots with defaults, ECRC is disabled.
- User enables ECRC via sysfs.
- What happens here?  ECRC is enabled via AER Control but not via
  DWC TD bit.  I assume ECRC doesn't work.  Does it cause PCIe
  errors (malformed TLP, etc)?


Since DWC TD bit is not programmed, for all the transactions that go through
ATU, TLP Digest won't get generated (although AER registers indicate that
ECRC should get generated).
As per the spec section "2.7.1 ECRC Rules"

---
If a device Function is enabled to generate ECRC, it must calculate and
apply ECRC for all TLPs originated by the Function
---

So the RP would be violating the PCIe spec, but it doesn't result in any
error because the same section has the following rule as well

---
If a device Function is enabled to check ECRC, it must do so for all TLPs
with ECRC where the device is the ultimate PCI Express Receiver
   Note that it is still possible for the Function to receive TLPs without
ECRC, and these are processed normally - this is not an error
---

so, even if the EP has ECRC check enabled, because of the above rule, it
just processes those packets without ECRC as normal packets.
Basically, whoever is enabling ECRC run time gets cheated as transactions
routed through ATU don't really have ECRC digest


Or this one:

- User boots with "pci=ecrc=on", ECRC is enabled.
- ECRC works fine.
- User disables ECRC via sysfs.
- What happens here?  ECRC is disabled via AER Control, but DWC TD
  bit thinks it's still enabled.


In this case, the EP doesn't have ECRC check enabled but receives TLPs with
ECRC digest. This again won't result in any error because of the section
"2.2.3 TLP Digest Rules" which says

---
If an intermediate or ultimate PCI Express Receiver of the TLP does not
support ECRC checking, the Receiver must ignore the TLP Digest
---

So the EP just ignores the TLP Digest and process the TLP normally.
Although functionality wise there is no issue here, there could be some
impact on the perf because of the extra DWord data. This is again debatable
as th

Re: [PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-11-04 Thread Vidya Sagar




On 11/4/2020 2:37 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Tue, Nov 03, 2020 at 08:57:01AM +0530, Vidya Sagar wrote:

On 11/3/2020 4:32 AM, Bjorn Helgaas wrote:

On Thu, Oct 29, 2020 at 11:09:59AM +0530, Vidya Sagar wrote:

DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.


I guess this is a hardware defect, right?

Yes. This is common across all DWC implementations (version 4.90 precisely)


How much of a problem would it be if we instead added a "no_ecrc"
quirk for this hardware so we never enabled ECRC?

Well, on Tegra for some of the high fidelity use cases, ECRC is required to
be turned on and if it can be done safely with these patches, why shouldn't
we not enable ECRC at all?


IIUC, the current Linux support of ECRC is a single choice at
boot-time: by default ECRC is not enabled, but if you boot with
"pci=ecrc=on", we turn on ECRC for every device.

That seems like the minimal support, but I think the spec allows ECRC
to be enabled selectively, on individual devices.  I can imagine a
sysfs knob that would allow us to enable/disable ECRC per-device at
run-time.

If we had such a sysfs knob, it would be pretty ugly and maybe
impractical to work around this hardware issue.  So I'm a little bit
hesitant to add functionality that might have to be removed in the
future.


Agree with this. But since it is a boot-time choice at this point, I think
we can still go ahead with this approach to have a working ECRC mechanism
right? I don't see any sysfs knob for AER controlling at this point.


I don't want to do anything that will prevent us from adding
per-device ECRC control in the future.

My concern is that if we add a run-time sysfs knob in the future, the
user experience on this hardware will be poor because there's no
convenient path to twiddle the PCIE_ATU_TD bit when the generic code
changes the AER Control bit.

Agree.
Can we add it to the documentation that run time changing of ECRC 
settings are not supported on this (i.e. Tegra194) platform (or for that 
matter on any SoC with PCIe based on DesignWare core version 4.90A). By 
'not supported', I meant that the ECRC digest part may not work but the 
normal functionality will continue to work without reporting any AER 
errors. I tried to emulate the following scenarios on Tegra194 silicon 
and here are my observations.

FWIW, I'm referring to the PCIe spec Rev 5.0 Ver 1.0 (22 May 2019)



What is the failure mode in these scenarios:

   - User boots with defaults, ECRC is disabled.
   - User enables ECRC via sysfs.
   - What happens here?  ECRC is enabled via AER Control but not via
 DWC TD bit.  I assume ECRC doesn't work.  Does it cause PCIe
 errors (malformed TLP, etc)?
Since DWC TD bit is not programmed, for all the transactions that go 
through ATU, TLP Digest won't get generated (although AER registers 
indicate that ECRC should get generated).

As per the spec section "2.7.1 ECRC Rules"

---
If a device Function is enabled to generate ECRC, it must calculate and 
apply ECRC for all TLPs originated by the Function

---

So the RP would be violating the PCIe spec, but it doesn't result in any 
error because the same section has the following rule as well


---
If a device Function is enabled to check ECRC, it must do so for all 
TLPs with ECRC where the device is the ultimate PCI Express Receiver
	Note that it is still possible for the Function to receive TLPs without 
ECRC, and these are processed normally - this is not an error

---

so, even if the EP has ECRC check enabled, because of the above rule, it 
just processes those packets without ECRC as normal packets.
Basically, whoever is enabling ECRC run time gets cheated as 
transactions routed through ATU don't really have ECRC digest




Or this one:

   - User boots with "pci=ecrc=on", ECRC is enabled.
   - ECRC works fine.
   - User disables ECRC via sysfs.
   - What happens here?  ECRC is disabled via AER Control, but DWC TD
 bit thinks it's still enabled.
In this case, the EP doesn't have ECRC check enabled but receives TLPs 
with ECRC digest. This again won't result in any error because of the 
section "2.2.3 TLP Digest Rules" which says


---
If an intermediate or ultimate PCI Express Receiver of the TLP does not 
support ECRC checking, the Receiver must ignore the TLP Digest

---

So the EP just ignores the TLP Digest and process the TLP normally.
Although functionality wise there is no issue here, there could be some 
impact on the perf because of the extra DWord data. This is again 
debatable as the perf/data path is typically from EP's DMA engine to 
host system memory and not config/BAR acce

[PATCH V3 0/5] Enhancements to Tegra194 PCIe driver

2020-11-04 Thread Vidya Sagar
This series of patches do some enhancements and some bug fixes to the
Tegra194 PCIe platform driver like
- Fix Vendor-ID corruption
- Map DBI space correctly
- Update DWC IP version
- Continue with uninitialization sequence even if parts fail
- Check return value of tegra_pcie_init_controller()

V3:
* Addressed Bjorn's review comments
* Split earlier patch-4 into two
  - Continue with the uninitialization sequence even if some parts fail
  - Check return value of tegra_pcie_init_controller() and exit accordingly

V2:
* Addressed Rob's comments. Changed 'Strongly Ordered' to 'nGnRnE'

Vidya Sagar (5):
  PCI: tegra: Fix ASPM-L1SS advertisement disable code
  PCI: tegra: Map configuration space as nGnRnE
  PCI: tegra: Set DesignWare IP version
  PCI: tegra: Continue unconfig sequence even if parts fail
  PCI: tegra: Check return value of tegra_pcie_init_controller()

 drivers/pci/controller/dwc/pcie-tegra194.c | 62 +++---
 1 file changed, 30 insertions(+), 32 deletions(-)

-- 
2.17.1



[PATCH V3 4/5] PCI: tegra: Continue unconfig sequence even if parts fail

2020-11-04 Thread Vidya Sagar
Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.

Signed-off-by: Vidya Sagar 
---
V3:
* Modified subject as per Bjorn's suggestion
* Removed tegra_pcie_init_controller()'s error checking part and pushed
  a separate patch for it

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 39 +-
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 253d91033bc3..9be10c8953df 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1422,43 +1422,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
int ret;
 
ret = reset_control_assert(pcie->core_rst);
-   if (ret) {
-   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-   ret);
-   return ret;
-   }
+   if (ret)
+   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", 
ret);
 
tegra_pcie_disable_phy(pcie);
 
ret = reset_control_assert(pcie->core_apb_rst);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-   return ret;
-   }
 
clk_disable_unprepare(pcie->core_clk);
 
ret = regulator_disable(pcie->pex_ctl_supply);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-   return ret;
-   }
 
tegra_pcie_disable_slot_regulators(pcie);
 
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
-   return ret;
-   }
-
-   return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1482,7 +1471,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1551,13 +1541,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(>pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
-
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -2238,8 +2227,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
   PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 
-   return __deinit_controller(pcie);
+   return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2267,7 +2257,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2305,7 +2296,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device 
*pdev)
disable_irq(pcie->pci.pp.msi_irq);
 
tegra_pcie_dw_pme_turnoff(pcie);
-   __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
-- 
2.17.1



[PATCH V3 2/5] PCI: tegra: Map configuration space as nGnRnE

2020-11-04 Thread Vidya Sagar
As specified in the comment for pci_remap_cfgspace() define in
arch/arm64/include/asm/io.h file, PCIe configuration space should be
mapped as nGnRnE. Hence changing to dev_pci_remap_cfgspace() from
devm_ioremap_resource() for mapping DBI space as that is nothing but
the root port's own configuration space.

Signed-off-by: Vidya Sagar 
---
V3:
* None

V2:
* Changed 'Strongly Ordered' to 'nGnRnE'

 drivers/pci/controller/dwc/pcie-tegra194.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index b172b1d49713..7a0c64436861 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2108,7 +2108,9 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
}
pcie->dbi_res = dbi_res;
 
-   pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
+   pci->dbi_base = devm_pci_remap_cfgspace(dev,
+   dbi_res->start,
+   resource_size(dbi_res));
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
 
-- 
2.17.1



[PATCH V3 1/5] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-11-04 Thread Vidya Sagar
If the absence of CLKREQ# signal is indicated by the absence of
"supports-clkreq" in the device-tree node, current driver is disabling
the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States
offset is correctly initialized. Since default value of the ASPM-L1SS
offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2
instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are
not being applied. This patch fixes this issue by refactoring the
code that disables the ASPM-L1SS advertisement.

Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar 
---
V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index aa511ec0d800..b172b1d49713 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -896,6 +896,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
init_host_aspm(pcie);
 
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@@ -1400,12 +1406,6 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
  PCI_CAP_ID_EXP);
 
-   /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
return ret;
 
 fail_phy:
-- 
2.17.1



Re: [PATCH V2 4/4] PCI: tegra: Handle error conditions properly

2020-11-04 Thread Vidya Sagar




On 11/4/2020 2:18 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


Hi Vidya,

Can you update the subject to replace "properly" with more details
about what the patch is doing?  "Properly" is really meaningless in
usages like this -- nobody writes patches to do the *wrong* thing, so
it goes without saying that every patch is intended to things
"properly".

It would also help to have some context.  My first thought was that
"error conditions" referred to PCIe errors like completion timeouts,
completer abort, etc.

Maybe something like:

   PCI: tegra: Continue unconfig sequence even if parts fail

Thanks for reviewing the change.
Sure. I'll go with the above subject line.


   PCI: tegra: Return init error (not unconfig error) on init failure

On Thu, Oct 29, 2020 at 10:48:39AM +0530, Vidya Sagar wrote:

Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.
It also adds checking return value for error for a cleaner exit path.


This paragraph uses "it" to refer to both "the driver" (second
sentence) and "this patch" (last sentence).  That's confusing.
There's no reason to refer to "this patch" at all.  I'd rather have
"Add checking ..." than "It adds checking ..."

I think that last sentence must be referring to the
tegra_pcie_init_controller() change to return the initialization error
rather than the error from __deinit_controller().  That seems right,
but should be a separate patch.

Sure. I'll push a new patch for this.




Signed-off-by: Vidya Sagar 
---
V2:
* None

  drivers/pci/controller/dwc/pcie-tegra194.c | 45 ++
  1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 253d91033bc3..8c08998b9ce1 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1422,43 +1422,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
   return ret;
  }

-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
  {
   int ret;

   ret = reset_control_assert(pcie->core_rst);
- if (ret) {
- dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", ret);

   tegra_pcie_disable_phy(pcie);

   ret = reset_control_assert(pcie->core_apb_rst);
- if (ret) {
+ if (ret)
   dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
- return ret;
- }

   clk_disable_unprepare(pcie->core_clk);

   ret = regulator_disable(pcie->pex_ctl_supply);
- if (ret) {
+ if (ret)
   dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
- return ret;
- }

   tegra_pcie_disable_slot_regulators(pcie);

   ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
- if (ret) {
+ if (ret)
   dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
   pcie->cid, ret);
- return ret;
- }
-
- return ret;
  }

  static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1482,7 +1471,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
   return 0;

  fail_host_init:
- return __deinit_controller(pcie);
+ tegra_pcie_unconfig_controller(pcie);
+ return ret;
  }

  static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1551,13 +1541,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
   appl_writel(pcie, data, APPL_PINMUX);
  }

-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
  {
   tegra_pcie_downstream_dev_to_D0(pcie);
   dw_pcie_host_deinit(>pci.pp);
   tegra_pcie_dw_pme_turnoff(pcie);
-
- return __deinit_controller(pcie);
+ tegra_pcie_unconfig_controller(pcie);
  }

  static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -1590,7 +1579,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
   goto fail_pm_get_sync;
   }

- tegra_pcie_init_controller(pcie);
+ ret = tegra_pcie_init_controller(pcie);
+ if (ret < 0) {
+ dev_err(dev, "

[PATCH V3 5/5] PCI: tegra: Check return value of tegra_pcie_init_controller()

2020-11-04 Thread Vidya Sagar
The return value of tegra_pcie_init_controller() must be checked before
PCIe link up check and registering debugfs entries subsequently as it
doesn't make sense to do these when the controller initialization itself
has failed.

Signed-off-by: Vidya Sagar 
---
V3:
* New patch in this series

 drivers/pci/controller/dwc/pcie-tegra194.c | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 9be10c8953df..8c08998b9ce1 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1579,7 +1579,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
goto fail_pm_get_sync;
}
 
-   tegra_pcie_init_controller(pcie);
+   ret = tegra_pcie_init_controller(pcie);
+   if (ret < 0) {
+   dev_err(dev, "Failed to initialize controller: %d\n", ret);
+   goto fail_pm_get_sync;
+   }
 
pcie->link_state = tegra_pcie_dw_link_up(>pci);
if (!pcie->link_state) {
-- 
2.17.1



[PATCH V3 3/5] PCI: tegra: Set DesignWare IP version

2020-11-04 Thread Vidya Sagar
Set the DesignWare IP version for Tegra194 to 0x490A. This would be used
by the DesigWare sub-system to do any version specific configuration
(Ex:- TD bit programming for ECRC).

Signed-off-by: Vidya Sagar 
---
V3:
* None

V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 7a0c64436861..253d91033bc3 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2011,6 +2011,7 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
pci->ops = _dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
+   pci->version = 0x490A;
 
pp = >pp;
pcie->dev = >dev;
-- 
2.17.1



Re: [PATCH 0/3] Add support to handle prefetchable memory

2020-11-03 Thread Vidya Sagar

Lorenzo / Bjorn,
Could you please review patches-1 & 2 in this series?
For the third patch, we already went with Rob's patch @ 
http://patchwork.ozlabs.org/project/linux-pci/patch/20201026154852.221483-1-r...@kernel.org/


Thanks,
Vidya Sagar

On 10/26/2020 6:02 PM, Thierry Reding wrote:

On Sat, Oct 24, 2020 at 04:03:41AM +, Jingoo Han wrote:

On 10/23/20, 3:57 PM, Vidya Sagar wrote:


This patch series adds support for configuring the DesignWare IP's ATU
region for prefetchable memory translations.
It first starts by flagging a warning if the size of non-prefetchable
aperture goes beyond 32-bit as PCIe spec doesn't allow it.
And then adds required support for programming the ATU to handle higher
(i.e. >4GB) sizes and then finally adds support for differentiating
between prefetchable and non-prefetchable regions and configuring one of
the ATU regions for prefetchable memory translations purpose.

Vidya Sagar (3):
   PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit
   PCI: dwc: Add support to program ATU for >4GB memory aperture sizes
   PCI: dwc: Add support to handle prefetchable memory mapping


For 2nd & 3rd,
Acked-by: Jingoo 
But, I still want someone to ack 1st patch, not me.

To Vidya,
If possible, can you ask your coworker to give 'Tested-by'? It will be very 
helpful.
Thank you.


On next-20201026 (but also going back quite a while) I'm seeing this
during boot on Jetson AGX Xavier (Tegra194):

[3.493382] ahci 0001:01:00.0: version 3.0
[3.493889] ahci 0001:01:00.0: SSS flag set, parallel bus scan disabled
[4.497706] ahci 0001:01:00.0: controller reset failed (0x)
[4.498114] ahci: probe of 0001:01:00.0 failed with error -5

After applying this series, AHCI over PCI is back to normal:

[3.543230] ahci 0001:01:00.0: AHCI 0001. 32 slots 1 ports 6 Gbps 0x1 
impl SATA mode
[3.550841] ahci 0001:01:00.0: flags: 64bit ncq sntf led only pmp fbs pio 
slum part sxs
[3.559747] scsi host0: ahci
[3.561998] ata1: SATA max UDMA/133 abar m512@0x123001 port 0x1230010100 
irq 63

So for the series:

Tested-by: Thierry Reding 



Re: [PATCH] PCI/ASPM: Save/restore ASPM-L1SS controls for suspend/resume

2020-11-03 Thread Vidya Sagar

Bjorn / Lorenzo,
Could you please review this change?

Thanks,
Vidya Sagar

On 10/25/2020 12:34 AM, Vidya Sagar wrote:

Previously ASPM L1-Sub-States control registers (CTL1 and CTL2) weren't
saved and restored during suspend/resume leading to ASPM-L1SS
configuration being lost post resume.

Save the ASPM-L1SS control registers so that the configuration is retained
post resume.

Signed-off-by: Vidya Sagar 
---
v1:
* It would be really good if someone can verify it on a non tegra194 platform

  drivers/pci/pci.c   |  7 +++
  drivers/pci/pci.h   |  4 
  drivers/pci/pcie/aspm.c | 41 +
  3 files changed, 52 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a458c46d7e39..034497264bde 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1551,6 +1551,7 @@ int pci_save_state(struct pci_dev *dev)
return i;
  
  	pci_save_ltr_state(dev);

+   pci_save_aspm_l1ss_state(dev);
pci_save_dpc_state(dev);
pci_save_aer_state(dev);
return pci_save_vc_state(dev);
@@ -1656,6 +1657,7 @@ void pci_restore_state(struct pci_dev *dev)
 * LTR itself (in the PCIe capability).
 */
pci_restore_ltr_state(dev);
+   pci_restore_aspm_l1ss_state(dev);
  
  	pci_restore_pcie_state(dev);

pci_restore_pasid_state(dev);
@@ -3319,6 +3321,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error)
pci_err(dev, "unable to allocate suspend buffer for LTR\n");
  
+	error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,

+   2 * sizeof(u32));
+   if (error)
+   pci_err(dev, "unable to allocate suspend buffer for 
ASPM-L1SS\n");
+
pci_allocate_vc_save_buffers(dev);
  }
  
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h

index fa12f7cbc1a0..8d2135f61e36 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -565,11 +565,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
  void pcie_aspm_exit_link_state(struct pci_dev *pdev);
  void pcie_aspm_pm_state_change(struct pci_dev *pdev);
  void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pci_save_aspm_l1ss_state(struct pci_dev *dev);
+void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
  #else
  static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
  static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
  static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
  static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
+static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
+static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
  #endif
  
  #ifdef CONFIG_PCIE_ECRC

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 253c30cc1967..d965bbc563ed 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -742,6 +742,47 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state 
*link, u32 state)
PCI_L1SS_CTL1_L1SS_MASK, val);
  }
  
+void pci_save_aspm_l1ss_state(struct pci_dev *dev)

+{
+   struct pci_cap_saved_state *save_state;
+   int aspm_l1ss;
+   u32 *cap;
+
+   if (!pci_is_pcie(dev))
+   return;
+
+   aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!aspm_l1ss)
+   return;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state)
+   return;
+
+   cap = (u32 *)_state->cap.data[0];
+   pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, cap++);
+   pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, cap++);
+}
+
+void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
+{
+   struct pci_cap_saved_state *save_state;
+   int aspm_l1ss;
+   u32 *cap;
+
+   if (!pci_is_pcie(dev))
+   return;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state || !aspm_l1ss)
+   return;
+
+   cap = (u32 *)_state->cap.data[0];
+   pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, *cap++);
+   pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, *cap++);
+}
+
  static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
  {
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,



Re: [PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-11-02 Thread Vidya Sagar




On 11/3/2020 4:32 AM, Bjorn Helgaas wrote:

External email: Use caution opening links or attachments


On Thu, Oct 29, 2020 at 11:09:59AM +0530, Vidya Sagar wrote:

DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.


I guess this is a hardware defect, right?

Yes. This is common across all DWC implementations (version 4.90 precisely)



How much of a problem would it be if we instead added a "no_ecrc"
quirk for this hardware so we never enabled ECRC?
Well, on Tegra for some of the high fidelity use cases, ECRC is required 
to be turned on and if it can be done safely with these patches, why 
shouldn't we not enable ECRC at all?




IIUC, the current Linux support of ECRC is a single choice at
boot-time: by default ECRC is not enabled, but if you boot with
"pci=ecrc=on", we turn on ECRC for every device.

That seems like the minimal support, but I think the spec allows ECRC
to be enabled selectively, on individual devices.  I can imagine a
sysfs knob that would allow us to enable/disable ECRC per-device at
run-time.

If we had such a sysfs knob, it would be pretty ugly and maybe
impractical to work around this hardware issue.  So I'm a little bit
hesitant to add functionality that might have to be removed in the
future.
Agree with this. But since it is a boot-time choice at this point, I 
think we can still go ahead with this approach to have a working ECRC 
mechanism right? I don't see any sysfs knob for AER controlling at this 
point.





Signed-off-by: Vidya Sagar 
Reviewed-by: Jingoo Han 
---
V3:
* Added 'Reviewed-by: Jingoo Han '

V2:
* Addressed Jingoo's review comment
* Removed saving 'td' bit information in 'dw_pcie' structure

  drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
  drivers/pci/controller/dwc/pcie-designware.h | 1 +
  2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..cbd651b219d2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -246,6 +246,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
   val = type | PCIE_ATU_FUNC_NUM(func_no);
+ if (pci->version == 0x490A)
+ val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
   val = upper_32_bits(size - 1) ?
   val | PCIE_ATU_INCREASE_REGION_SIZE : val;
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -294,8 +296,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
  lower_32_bits(pci_addr));
   dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
  upper_32_bits(pci_addr));
- dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-PCIE_ATU_FUNC_NUM(func_no));
+ val = type | PCIE_ATU_FUNC_NUM(func_no);
+ if (pci->version == 0x490A)
+ val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
+ dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
   dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);

   /*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index e7f441441db2..b01ef407fd52 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -89,6 +89,7 @@
  #define PCIE_ATU_TYPE_IO 0x2
  #define PCIE_ATU_TYPE_CFG0   0x4
  #define PCIE_ATU_TYPE_CFG1   0x5
+#define PCIE_ATU_TD_SHIFT8
  #define PCIE_ATU_FUNC_NUM(pf)   ((pf) << 20)
  #define PCIE_ATU_CR2 0x908
  #define PCIE_ATU_ENABLE  BIT(31)
--
2.17.1



Re: [PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-11-02 Thread Vidya Sagar




On 11/2/2020 7:45 PM, Rob Herring wrote:

External email: Use caution opening links or attachments


On Thu, Oct 29, 2020 at 12:40 AM Vidya Sagar  wrote:


DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
Reviewed-by: Jingoo Han 
---
V3:
* Added 'Reviewed-by: Jingoo Han '

V2:
* Addressed Jingoo's review comment
* Removed saving 'td' bit information in 'dw_pcie' structure

  drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
  drivers/pci/controller/dwc/pcie-designware.h | 1 +
  2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..cbd651b219d2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -246,6 +246,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
 dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
  upper_32_bits(pci_addr));
 val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
 val = upper_32_bits(size - 1) ?
 val | PCIE_ATU_INCREASE_REGION_SIZE : val;
 dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -294,8 +296,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
lower_32_bits(pci_addr));
 dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)


Is this even possible? Are the non-unroll ATU registers available post 4.80?
I'm not sure. Gustavo might have information about this. I made this 
change so that it is taken care off even if they available.




Rob



Re: [PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-10-30 Thread Vidya Sagar




On 10/30/2020 3:33 AM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 10/29/20, 1:40 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
Reviewed-by: Jingoo Han 


No, it should be Acked-by. I gave you Acked-by, not Reviewed-by.

Acked-by: Jingoo Han 
Apologies. My bad. I saw the 'Reviewed-by' of the other patch (i.e. 
PCI/AER: Add pcie_is_ecrc_enabled() API) and put that for this patch as 
well. I'll update.





Best regards,
Jingoo Han


---
V3:
* Added 'Reviewed-by: Jingoo Han '

V2:
* Addressed Jingoo's review comment
* Removed saving 'td' bit information in 'dw_pcie' structure

  drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
  drivers/pci/controller/dwc/pcie-designware.h | 1 +
  2 files changed, 7 insertions(+), 2 deletions(-)


[...]



[PATCH V2 1/4] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-10-29 Thread Vidya Sagar
If the absence of CLKREQ# signal is indicated by the absence of
"supports-clkreq" in the device-tree node, current driver is disabling
the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States
offset is correctly initialized. Since default value of the ASPM-L1SS
offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2
instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are
not being applied. This patch fixes this issue by refactoring the
code that disables the ASPM-L1SS advertisement.

Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar 
---
V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index aa511ec0d800..b172b1d49713 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -896,6 +896,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
init_host_aspm(pcie);
 
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@@ -1400,12 +1406,6 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
  PCI_CAP_ID_EXP);
 
-   /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
return ret;
 
 fail_phy:
-- 
2.17.1



[PATCH V2 3/4] PCI: tegra: Set DesignWare IP version

2020-10-29 Thread Vidya Sagar
Set the DesignWare IP version for Tegra194 to 0x490A. This would be used
by the DesigWare sub-system to do any version specific configuration
(Ex:- TD bit programming for ECRC).

Signed-off-by: Vidya Sagar 
---
V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 7a0c64436861..253d91033bc3 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2011,6 +2011,7 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
pci->ops = _dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
+   pci->version = 0x490A;
 
pp = >pp;
pcie->dev = >dev;
-- 
2.17.1



[PATCH V2 2/4] PCI: tegra: Map configuration space as nGnRnE

2020-10-29 Thread Vidya Sagar
As specified in the comment for pci_remap_cfgspace() define in
arch/arm64/include/asm/io.h file, PCIe configuration space should be
mapped as nGnRnE. Hence changing to dev_pci_remap_cfgspace() from
devm_ioremap_resource() for mapping DBI space as that is nothing but
the root port's own configuration space.

Signed-off-by: Vidya Sagar 
---
V2:
* Changed 'Strongly Ordered' to 'nGnRnE'

 drivers/pci/controller/dwc/pcie-tegra194.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index b172b1d49713..7a0c64436861 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2108,7 +2108,9 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
}
pcie->dbi_res = dbi_res;
 
-   pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
+   pci->dbi_base = devm_pci_remap_cfgspace(dev,
+   dbi_res->start,
+   resource_size(dbi_res));
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
 
-- 
2.17.1



[PATCH V3 0/2] Add support to configure DWC for ECRC

2020-10-29 Thread Vidya Sagar
This series has two patches.

Patch-1: Adds a public API to query if the system has ECRC policty turned on.

Patch-2: DesignWare core PCIe IP has a TLP Digest (TD) override bit in one of
its control registers of ATU. This bit needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. DWC code queries the PCIe sub-system through the API added
in Patch-1 to find out if ECRC is turned on or not and configures ATU
accordingly.

V3:
* Addressed Ethan Zhao's comments for patch-1

V2:
* Addressed Jingoo's review comments

Vidya Sagar (2):
  PCI/AER: Add pcie_is_ecrc_enabled() API
  PCI: dwc: Add support to configure for ECRC

 drivers/pci/controller/dwc/pcie-designware.c |  8 ++--
 drivers/pci/controller/dwc/pcie-designware.h |  1 +
 drivers/pci/pci.h|  2 ++
 drivers/pci/pcie/aer.c   | 11 +++
 4 files changed, 20 insertions(+), 2 deletions(-)

-- 
2.17.1



[PATCH V3 2/2] PCI: dwc: Add support to configure for ECRC

2020-10-29 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
Reviewed-by: Jingoo Han 
---
V3:
* Added 'Reviewed-by: Jingoo Han '

V2:
* Addressed Jingoo's review comment
* Removed saving 'td' bit information in 'dw_pcie' structure

 drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
 drivers/pci/controller/dwc/pcie-designware.h | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..cbd651b219d2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -246,6 +246,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -294,8 +296,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
+   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index e7f441441db2..b01ef407fd52 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -89,6 +89,7 @@
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
 #define PCIE_ATU_TYPE_CFG1 0x5
+#define PCIE_ATU_TD_SHIFT  8
 #define PCIE_ATU_FUNC_NUM(pf)   ((pf) << 20)
 #define PCIE_ATU_CR2   0x908
 #define PCIE_ATU_ENABLEBIT(31)
-- 
2.17.1



[PATCH V3 1/2] PCI/AER: Add pcie_is_ecrc_enabled() API

2020-10-29 Thread Vidya Sagar
Adds pcie_is_ecrc_enabled() API to let other sub-systems (like DesignWare)
to query if ECRC policy is enabled and perform any configuration
required in those respective sub-systems.

Signed-off-by: Vidya Sagar 
Reviewed-by: Jingoo Han 
---
V3:
* Address Ethan Zhao's comments
* Added 'Reviewed-by: Jingoo Han '

V2:
* None from V1

 drivers/pci/pci.h  |  2 ++
 drivers/pci/pcie/aer.c | 11 +++
 2 files changed, 13 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fa12f7cbc1a0..325fdbf91dde 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -575,9 +575,11 @@ static inline void pcie_aspm_powersave_config_link(struct 
pci_dev *pdev) { }
 #ifdef CONFIG_PCIE_ECRC
 void pcie_set_ecrc_checking(struct pci_dev *dev);
 void pcie_ecrc_get_policy(char *str);
+bool pcie_is_ecrc_enabled(void);
 #else
 static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { }
 static inline void pcie_ecrc_get_policy(char *str) { }
+static inline bool pcie_is_ecrc_enabled(void) { return false; }
 #endif
 
 #ifdef CONFIG_PCIE_PTM
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 65dff5f3457a..d0f5a7043aff 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -207,6 +207,17 @@ void pcie_ecrc_get_policy(char *str)
 
ecrc_policy = i;
 }
+
+/**
+ * pcie_is_ecrc_enabled - returns if ECRC is enabled in the system or not
+ *
+ * Returns true if ECRC policy is enabled and false otherwise
+ */
+bool pcie_is_ecrc_enabled(void)
+{
+   return ecrc_policy == ECRC_POLICY_ON;
+}
+EXPORT_SYMBOL(pcie_is_ecrc_enabled);
 #endif /* CONFIG_PCIE_ECRC */
 
 #definePCI_EXP_AER_FLAGS   (PCI_EXP_DEVCTL_CERE | 
PCI_EXP_DEVCTL_NFERE | \
-- 
2.17.1



[PATCH V2 4/4] PCI: tegra: Handle error conditions properly

2020-10-29 Thread Vidya Sagar
Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.
It also adds checking return value for error for a cleaner exit path.

Signed-off-by: Vidya Sagar 
---
V2:
* None

 drivers/pci/controller/dwc/pcie-tegra194.c | 45 ++
 1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 253d91033bc3..8c08998b9ce1 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1422,43 +1422,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
int ret;
 
ret = reset_control_assert(pcie->core_rst);
-   if (ret) {
-   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-   ret);
-   return ret;
-   }
+   if (ret)
+   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", 
ret);
 
tegra_pcie_disable_phy(pcie);
 
ret = reset_control_assert(pcie->core_apb_rst);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-   return ret;
-   }
 
clk_disable_unprepare(pcie->core_clk);
 
ret = regulator_disable(pcie->pex_ctl_supply);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-   return ret;
-   }
 
tegra_pcie_disable_slot_regulators(pcie);
 
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
-   return ret;
-   }
-
-   return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1482,7 +1471,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1551,13 +1541,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(>pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
-
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -1590,7 +1579,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
goto fail_pm_get_sync;
}
 
-   tegra_pcie_init_controller(pcie);
+   ret = tegra_pcie_init_controller(pcie);
+   if (ret < 0) {
+   dev_err(dev, "Failed to initialize controller: %d\n", ret);
+   goto fail_pm_get_sync;
+   }
 
pcie->link_state = tegra_pcie_dw_link_up(>pci);
if (!pcie->link_state) {
@@ -2238,8 +2231,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
   PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 
-   return __deinit_controller(pcie);
+   return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2267,7 +2261,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2305,7 +2300,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device 
*pdev)
disable_irq(pcie->pci.pp.msi_irq);
 
tegra_pcie_dw_pme_turnoff(pcie);
-   __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
-- 
2.17.1



[PATCH V2 0/4] Enhancements to Tegra194 PCIe driver

2020-10-29 Thread Vidya Sagar
This series of patches do some enhancements and some bug fixes to the
Tegra194 PCIe platform driver like
- Fixing Vendor-ID corruption
- Mapping DBI space correctly
- Updating DWC IP version
- Handling error conditions properly

V2;
* Addressed Rob's comments. Changed 'Strongly Ordered' to 'nGnRnE'

Vidya Sagar (4):
  PCI: tegra: Fix ASPM-L1SS advertisement disable code
  PCI: tegra: Map configuration space as nGnRnE
  PCI: tegra: Set DesignWare IP version
  PCI: tegra: Handle error conditions properly

 drivers/pci/controller/dwc/pcie-tegra194.c | 62 +++---
 1 file changed, 30 insertions(+), 32 deletions(-)

-- 
2.17.1



[PATCH V2 2/2] PCI: dwc: Add support to configure for ECRC

2020-10-27 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
---
V2:
* Addressed Jingoo's review comment
* Removed saving 'td' bit information in 'dw_pcie' structure

 drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
 drivers/pci/controller/dwc/pcie-designware.h | 1 +
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..cbd651b219d2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -246,6 +246,8 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -294,8 +296,10 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   lower_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
-   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   if (pci->version == 0x490A)
+   val = val | pcie_is_ecrc_enabled() << PCIE_ATU_TD_SHIFT;
+   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 21dd06831b50..e5449b205c22 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -90,6 +90,7 @@
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
 #define PCIE_ATU_TYPE_CFG1 0x5
+#define PCIE_ATU_TD_SHIFT  8
 #define PCIE_ATU_FUNC_NUM(pf)   ((pf) << 20)
 #define PCIE_ATU_CR2   0x908
 #define PCIE_ATU_ENABLEBIT(31)
-- 
2.17.1



[PATCH V2 1/2] PCI/AER: Add pcie_is_ecrc_enabled() API

2020-10-27 Thread Vidya Sagar
Adds pcie_is_ecrc_enabled() API to let other sub-systems (like DesignWare)
to query if ECRC policy is enabled and perform any configuration
required in those respective sub-systems.

Signed-off-by: Vidya Sagar 
---
V2:
* None from V1

 drivers/pci/pci.h  |  2 ++
 drivers/pci/pcie/aer.c | 11 +++
 2 files changed, 13 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fa12f7cbc1a0..325fdbf91dde 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -575,9 +575,11 @@ static inline void pcie_aspm_powersave_config_link(struct 
pci_dev *pdev) { }
 #ifdef CONFIG_PCIE_ECRC
 void pcie_set_ecrc_checking(struct pci_dev *dev);
 void pcie_ecrc_get_policy(char *str);
+bool pcie_is_ecrc_enabled(void);
 #else
 static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { }
 static inline void pcie_ecrc_get_policy(char *str) { }
+static inline bool pcie_is_ecrc_enabled(void) { return false; }
 #endif
 
 #ifdef CONFIG_PCIE_PTM
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 65dff5f3457a..24363c895aba 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -207,6 +207,17 @@ void pcie_ecrc_get_policy(char *str)
 
ecrc_policy = i;
 }
+
+/**
+ * pcie_is_ecrc_enabled - returns if ECRC is enabled in the system or not
+ *
+ * Returns 1 if ECRC policy is enabled and 0 otherwise
+ */
+bool pcie_is_ecrc_enabled(void)
+{
+   return ecrc_policy == ECRC_POLICY_ON;
+}
+EXPORT_SYMBOL(pcie_is_ecrc_enabled);
 #endif /* CONFIG_PCIE_ECRC */
 
 #definePCI_EXP_AER_FLAGS   (PCI_EXP_DEVCTL_CERE | 
PCI_EXP_DEVCTL_NFERE | \
-- 
2.17.1



[PATCH V2 0/2] Add support to configure DWC for ECRC

2020-10-27 Thread Vidya Sagar
This series has two patches.

Patch-1: Adds a public API to query if the system has ECRC policty turned on.

Patch-2: DesignWare core PCIe IP has a TLP Digest (TD) override bit in one of
its control registers of ATU. This bit needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. DWC code queries the PCIe sub-system through the API added
in Patch-1 to find out if ECRC is turned on or not and configures ATU
accordingly.

V2:
* Addressed Jingoo's review comments

Vidya Sagar (2):
  PCI/AER: Add pcie_is_ecrc_enabled() API
  PCI: dwc: Add support to configure for ECRC

 drivers/pci/controller/dwc/pcie-designware.c |  8 ++--
 drivers/pci/controller/dwc/pcie-designware.h |  1 +
 drivers/pci/pci.h|  2 ++
 drivers/pci/pcie/aer.c   | 11 +++
 4 files changed, 20 insertions(+), 2 deletions(-)

-- 
2.17.1



Re: [PATCH 2/2] PCI: dwc: Add support to configure for ECRC

2020-10-26 Thread Vidya Sagar




On 10/26/2020 2:19 AM, Jingoo Han wrote:

External email: Use caution opening links or attachments


On 10/25/20, 3:31 AM, Vidya Sagar wrote:


DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
---
  drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
  drivers/pci/controller/dwc/pcie-designware.h | 2 ++
  2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..810dcbdbe869 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -245,7 +245,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
lower_32_bits(pci_addr));
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
- val = type | PCIE_ATU_FUNC_NUM(func_no);
+ val = type | PCIE_ATU_FUNC_NUM(func_no) | pci->td << PCIE_ATU_TD_SHIFT;
   val = upper_32_bits(size - 1) ?
   val | PCIE_ATU_INCREASE_REGION_SIZE : val;
   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -295,7 +295,8 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
   dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
  upper_32_bits(pci_addr));
   dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-PCIE_ATU_FUNC_NUM(func_no));
+PCIE_ATU_FUNC_NUM(func_no) |
+pci->td << PCIE_ATU_TD_SHIFT);
   dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);

   /*
@@ -565,6 +566,9 @@ void dw_pcie_setup(struct dw_pcie *pci)
   dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
   "enabled" : "disabled");

+ if (pci->version == 0x490A)
+ pci->td = pcie_is_ecrc_enabled();
+
   if (pci->link_gen > 0)
   dw_pcie_link_set_max_speed(pci, pci->link_gen);

diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 21dd06831b50..d34723e42e79 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -90,6 +90,7 @@
  #define PCIE_ATU_TYPE_IO 0x2
  #define PCIE_ATU_TYPE_CFG0   0x4
  #define PCIE_ATU_TYPE_CFG1   0x5
+#define PCIE_ATU_TD_SHIFT8
  #define PCIE_ATU_FUNC_NUM(pf)   ((pf) << 20)
  #define PCIE_ATU_CR2 0x908
  #define PCIE_ATU_ENABLE  BIT(31)
@@ -276,6 +277,7 @@ struct dw_pcie {
   int num_lanes;
   int link_gen;
   u8  n_fts[2];
+ booltd; /* TLP Digest (for ECRC purpose) */


If possible, don't add a new variable to 'dw_pcie' structure.
Please find a way to set TD bit without adding a new variable to 'dw_pcie' 
structure'.


I can use pcie_is_ecrc_enabled() directly in place of pci->td. That 
should be fine right? BTW, curious to know if there is any specific 
reason behind asking not to add any new variables to 'dw_pcie' structure?




Best regards,
Jingoo Han


  };

  #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
--
2.17.1




[PATCH 3/4] PCI: tegra: Set DesignWare IP version

2020-10-26 Thread Vidya Sagar
Set the DesignWare IP version for Tegra194 to 0x490A. This would be used
by the DesigWare sub-system to do any version specific configuration
(Ex:- TD bit programming for ECRC).

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 7a0c64436861..253d91033bc3 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2011,6 +2011,7 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
pci->ops = _dw_pcie_ops;
pci->n_fts[0] = N_FTS_VAL;
pci->n_fts[1] = FTS_VAL;
+   pci->version = 0x490A;
 
pp = >pp;
pcie->dev = >dev;
-- 
2.17.1



[PATCH 4/4] PCI: tegra: Handle error conditions properly

2020-10-26 Thread Vidya Sagar
Currently the driver checks for error value of different APIs during the
uninitialization sequence. It just returns from there if there is any error
observed for one of those calls. Comparatively it is better to continue the
uninitialization sequence irrespective of whether some of them are
returning error. That way, it is more closer to complete uninitialization.
It also adds checking return value for error for a cleaner exit path.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 45 ++
 1 file changed, 20 insertions(+), 25 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index 253d91033bc3..8c08998b9ce1 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -1422,43 +1422,32 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
return ret;
 }
 
-static int __deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_unconfig_controller(struct tegra_pcie_dw *pcie)
 {
int ret;
 
ret = reset_control_assert(pcie->core_rst);
-   if (ret) {
-   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n",
-   ret);
-   return ret;
-   }
+   if (ret)
+   dev_err(pcie->dev, "Failed to assert \"core\" reset: %d\n", 
ret);
 
tegra_pcie_disable_phy(pcie);
 
ret = reset_control_assert(pcie->core_apb_rst);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to assert APB reset: %d\n", ret);
-   return ret;
-   }
 
clk_disable_unprepare(pcie->core_clk);
 
ret = regulator_disable(pcie->pex_ctl_supply);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable regulator: %d\n", ret);
-   return ret;
-   }
 
tegra_pcie_disable_slot_regulators(pcie);
 
ret = tegra_pcie_bpmp_set_ctrl_state(pcie, false);
-   if (ret) {
+   if (ret)
dev_err(pcie->dev, "Failed to disable controller %d: %d\n",
pcie->cid, ret);
-   return ret;
-   }
-
-   return ret;
 }
 
 static int tegra_pcie_init_controller(struct tegra_pcie_dw *pcie)
@@ -1482,7 +1471,8 @@ static int tegra_pcie_init_controller(struct 
tegra_pcie_dw *pcie)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_try_link_l2(struct tegra_pcie_dw *pcie)
@@ -1551,13 +1541,12 @@ static void tegra_pcie_dw_pme_turnoff(struct 
tegra_pcie_dw *pcie)
appl_writel(pcie, data, APPL_PINMUX);
 }
 
-static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+static void tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
 {
tegra_pcie_downstream_dev_to_D0(pcie);
dw_pcie_host_deinit(>pci.pp);
tegra_pcie_dw_pme_turnoff(pcie);
-
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
@@ -1590,7 +1579,11 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw 
*pcie)
goto fail_pm_get_sync;
}
 
-   tegra_pcie_init_controller(pcie);
+   ret = tegra_pcie_init_controller(pcie);
+   if (ret < 0) {
+   dev_err(dev, "Failed to initialize controller: %d\n", ret);
+   goto fail_pm_get_sync;
+   }
 
pcie->link_state = tegra_pcie_dw_link_up(>pci);
if (!pcie->link_state) {
@@ -2238,8 +2231,9 @@ static int tegra_pcie_dw_suspend_noirq(struct device *dev)
   PORT_LOGIC_MSI_CTRL_INT_0_EN);
tegra_pcie_downstream_dev_to_D0(pcie);
tegra_pcie_dw_pme_turnoff(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 
-   return __deinit_controller(pcie);
+   return 0;
 }
 
 static int tegra_pcie_dw_resume_noirq(struct device *dev)
@@ -2267,7 +2261,8 @@ static int tegra_pcie_dw_resume_noirq(struct device *dev)
return 0;
 
 fail_host_init:
-   return __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
+   return ret;
 }
 
 static int tegra_pcie_dw_resume_early(struct device *dev)
@@ -2305,7 +2300,7 @@ static void tegra_pcie_dw_shutdown(struct platform_device 
*pdev)
disable_irq(pcie->pci.pp.msi_irq);
 
tegra_pcie_dw_pme_turnoff(pcie);
-   __deinit_controller(pcie);
+   tegra_pcie_unconfig_controller(pcie);
 }
 
 static const struct tegra_pcie_dw_of_data tegra_pcie_dw_rc_of_data = {
-- 
2.17.1



[PATCH 0/4] Enhancements to Tegra194 PCIe driver

2020-10-26 Thread Vidya Sagar
This series of patches do some enhancements and some bug fixes to the
Tegra194 PCIe platform driver like
- Fixing Vendor-ID corruption
- Mapping DBI space correctly
- Updating DWC IP version
- Handling error conditions properly

Vidya Sagar (4):
  PCI: tegra: Fix ASPM-L1SS advertisement disable code
  PCI: tegra: Map configuration space as strongly ordered
  PCI: tegra: Set DesignWare IP version
  PCI: tegra: Handle error conditions properly

 drivers/pci/controller/dwc/pcie-tegra194.c | 62 +++---
 1 file changed, 30 insertions(+), 32 deletions(-)

-- 
2.17.1



[PATCH 1/4] PCI: tegra: Fix ASPM-L1SS advertisement disable code

2020-10-26 Thread Vidya Sagar
If the absence of CLKREQ# signal is indicated by the absence of
"supports-clkreq" in the device-tree node, current driver is disabling
the advertisement of ASPM-L1 Sub-States *before* the ASPM-L1 Sub-States
offset is correctly initialized. Since default value of the ASPM-L1SS
offset is zero, this is causing the Vendor-ID wrongly programmed to 0x10d2
instead of Nvidia's 0x10de thereby the quirks applicable for Tegra194 are
not being applied. This patch fixes this issue by refactoring the
code that disables the ASPM-L1SS advertisement.

Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index aa511ec0d800..b172b1d49713 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -896,6 +896,12 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
 
init_host_aspm(pcie);
 
+   /* Disable ASPM-L1SS advertisement if there is no CLKREQ routing */
+   if (!pcie->supports_clkreq) {
+   disable_aspm_l11(pcie);
+   disable_aspm_l12(pcie);
+   }
+
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
@@ -1400,12 +1406,6 @@ static int tegra_pcie_config_controller(struct 
tegra_pcie_dw *pcie,
pcie->pcie_cap_base = dw_pcie_find_capability(>pci,
  PCI_CAP_ID_EXP);
 
-   /* Disable ASPM-L1SS advertisement as there is no CLKREQ routing */
-   if (!pcie->supports_clkreq) {
-   disable_aspm_l11(pcie);
-   disable_aspm_l12(pcie);
-   }
-
return ret;
 
 fail_phy:
-- 
2.17.1



[PATCH 2/4] PCI: tegra: Map configuration space as strongly ordered

2020-10-26 Thread Vidya Sagar
As specified in the comment for pci_remap_cfgspace() define in
arch/arm64/include/asm/io.h file, PCIe configuration space should be
mapped as strongly ordered. Hence changing to dev_pci_remap_cfgspace()
from devm_ioremap_resource() for mapping DBI space as that is nothing
but the root port's own configuration space.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-tegra194.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c 
b/drivers/pci/controller/dwc/pcie-tegra194.c
index b172b1d49713..7a0c64436861 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -2108,7 +2108,9 @@ static int tegra_pcie_dw_probe(struct platform_device 
*pdev)
}
pcie->dbi_res = dbi_res;
 
-   pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
+   pci->dbi_base = devm_pci_remap_cfgspace(dev,
+   dbi_res->start,
+   resource_size(dbi_res));
if (IS_ERR(pci->dbi_base))
return PTR_ERR(pci->dbi_base);
 
-- 
2.17.1



[PATCH 2/2] arm64: tegra: Fix DT binding for IO High Voltage entry

2020-10-26 Thread Vidya Sagar
Fix the device-tree entry that represents I/O High Voltage property
by replacing 'nvidia,io-high-voltage' with 'nvidia,io-hv' as the former
entry is deprecated.

Fixes: dbb72e2c305b ("arm64: tegra: Add configuration for PCIe C5 sideband 
signals")
Signed-off-by: Vidya Sagar 
---
 arch/arm64/boot/dts/nvidia/tegra194.dtsi | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi 
b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 48160f48003a..5007a2a8647c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -155,7 +155,7 @@
nvidia,schmitt = ;
nvidia,lpdr = ;
nvidia,enable-input = 
;
-   nvidia,io-high-voltage = 
;
+   nvidia,io-hv = ;
nvidia,tristate = ;
nvidia,pull = ;
};
@@ -167,7 +167,7 @@
nvidia,schmitt = ;
nvidia,lpdr = ;
nvidia,enable-input = 
;
-   nvidia,io-high-voltage = 
;
+   nvidia,io-hv = ;
nvidia,tristate = ;
nvidia,pull = ;
};
-- 
2.17.1



[PATCH 1/2] dt-bindings: Fix entry name for I/O High Voltage property

2020-10-26 Thread Vidya Sagar
Correct the name of the I/O High Voltage Property from
'nvidia,io-high-voltage' to 'nvidia,io-hv'.

Fixes: 2585a584f844 ("pinctrl: Add Tegra194 pinctrl DT bindings")
Signed-off-by: Vidya Sagar 
---
 .../devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt 
b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
index 8763f448c376..90d38f710635 100644
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra194-pinmux.txt
@@ -99,7 +99,7 @@ Example:
nvidia,schmitt = ;
nvidia,lpdr = ;
nvidia,enable-input = 
;
-   nvidia,io-high-voltage = 
;
+   nvidia,io-hv = ;
nvidia,tristate = ;
nvidia,pull = ;
};
-- 
2.17.1



[PATCH 0/2] Add support to configure DWC for ECRC

2020-10-25 Thread Vidya Sagar
This series has two patches.

Patch-1: Adds a public API to query if the system has ECRC policty turned on.

Patch-2: DesignWare core PCIe IP has a TLP Digest (TD) override bit in one of
its control registers of ATU. This bit needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. DWC code queries the PCIe sub-system through the API added
in Patch-1 to find out if ECRC is turned on or not and configures ATU
accordingly.

Vidya Sagar (2):
  PCI/AER: Add pcie_is_ecrc_enabled() API
  PCI: dwc: Add support to configure for ECRC

 drivers/pci/controller/dwc/pcie-designware.c |  8 ++--
 drivers/pci/controller/dwc/pcie-designware.h |  2 ++
 drivers/pci/pci.h|  2 ++
 drivers/pci/pcie/aer.c   | 11 +++
 4 files changed, 21 insertions(+), 2 deletions(-)

-- 
2.17.1



[PATCH 1/2] PCI/AER: Add pcie_is_ecrc_enabled() API

2020-10-25 Thread Vidya Sagar
Adds pcie_is_ecrc_enabled() API to let other sub-systems (like DesignWare)
to query if ECRC policy is enabled and perform any configuration
required in those respective sub-systems.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/pci.h  |  2 ++
 drivers/pci/pcie/aer.c | 11 +++
 2 files changed, 13 insertions(+)

diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fa12f7cbc1a0..325fdbf91dde 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -575,9 +575,11 @@ static inline void pcie_aspm_powersave_config_link(struct 
pci_dev *pdev) { }
 #ifdef CONFIG_PCIE_ECRC
 void pcie_set_ecrc_checking(struct pci_dev *dev);
 void pcie_ecrc_get_policy(char *str);
+bool pcie_is_ecrc_enabled(void);
 #else
 static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { }
 static inline void pcie_ecrc_get_policy(char *str) { }
+static inline bool pcie_is_ecrc_enabled(void) { return false; }
 #endif
 
 #ifdef CONFIG_PCIE_PTM
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 65dff5f3457a..24363c895aba 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -207,6 +207,17 @@ void pcie_ecrc_get_policy(char *str)
 
ecrc_policy = i;
 }
+
+/**
+ * pcie_is_ecrc_enabled - returns if ECRC is enabled in the system or not
+ *
+ * Returns 1 if ECRC policy is enabled and 0 otherwise
+ */
+bool pcie_is_ecrc_enabled(void)
+{
+   return ecrc_policy == ECRC_POLICY_ON;
+}
+EXPORT_SYMBOL(pcie_is_ecrc_enabled);
 #endif /* CONFIG_PCIE_ECRC */
 
 #definePCI_EXP_AER_FLAGS   (PCI_EXP_DEVCTL_CERE | 
PCI_EXP_DEVCTL_NFERE | \
-- 
2.17.1



[PATCH 2/2] PCI: dwc: Add support to configure for ECRC

2020-10-25 Thread Vidya Sagar
DesignWare core has a TLP digest (TD) override bit in one of the control
registers of ATU. This bit also needs to be programmed for proper ECRC
functionality. This is currently identified as an issue with DesignWare
IP version 4.90a. This patch does the required programming in ATU upon
querying the system policy for ECRC.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-designware.c | 8 ++--
 drivers/pci/controller/dwc/pcie-designware.h | 2 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index b5e438b70cd5..810dcbdbe869 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -245,7 +245,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   val = type | PCIE_ATU_FUNC_NUM(func_no) | pci->td << PCIE_ATU_TD_SHIFT;
val = upper_32_bits(size - 1) ?
val | PCIE_ATU_INCREASE_REGION_SIZE : val;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
@@ -295,7 +295,8 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
   upper_32_bits(pci_addr));
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
-  PCIE_ATU_FUNC_NUM(func_no));
+  PCIE_ATU_FUNC_NUM(func_no) |
+  pci->td << PCIE_ATU_TD_SHIFT);
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
 
/*
@@ -565,6 +566,9 @@ void dw_pcie_setup(struct dw_pcie *pci)
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
"enabled" : "disabled");
 
+   if (pci->version == 0x490A)
+   pci->td = pcie_is_ecrc_enabled();
+
if (pci->link_gen > 0)
dw_pcie_link_set_max_speed(pci, pci->link_gen);
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 21dd06831b50..d34723e42e79 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -90,6 +90,7 @@
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
 #define PCIE_ATU_TYPE_CFG1 0x5
+#define PCIE_ATU_TD_SHIFT  8
 #define PCIE_ATU_FUNC_NUM(pf)   ((pf) << 20)
 #define PCIE_ATU_CR2   0x908
 #define PCIE_ATU_ENABLEBIT(31)
@@ -276,6 +277,7 @@ struct dw_pcie {
int num_lanes;
int link_gen;
u8  n_fts[2];
+   booltd; /* TLP Digest (for ECRC purpose) */
 };
 
 #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
-- 
2.17.1



[PATCH] PCI/ASPM: Save/restore ASPM-L1SS controls for suspend/resume

2020-10-24 Thread Vidya Sagar
Previously ASPM L1-Sub-States control registers (CTL1 and CTL2) weren't
saved and restored during suspend/resume leading to ASPM-L1SS
configuration being lost post resume.

Save the ASPM-L1SS control registers so that the configuration is retained
post resume.

Signed-off-by: Vidya Sagar 
---
v1:
* It would be really good if someone can verify it on a non tegra194 platform

 drivers/pci/pci.c   |  7 +++
 drivers/pci/pci.h   |  4 
 drivers/pci/pcie/aspm.c | 41 +
 3 files changed, 52 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index a458c46d7e39..034497264bde 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1551,6 +1551,7 @@ int pci_save_state(struct pci_dev *dev)
return i;
 
pci_save_ltr_state(dev);
+   pci_save_aspm_l1ss_state(dev);
pci_save_dpc_state(dev);
pci_save_aer_state(dev);
return pci_save_vc_state(dev);
@@ -1656,6 +1657,7 @@ void pci_restore_state(struct pci_dev *dev)
 * LTR itself (in the PCIe capability).
 */
pci_restore_ltr_state(dev);
+   pci_restore_aspm_l1ss_state(dev);
 
pci_restore_pcie_state(dev);
pci_restore_pasid_state(dev);
@@ -3319,6 +3321,11 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev)
if (error)
pci_err(dev, "unable to allocate suspend buffer for LTR\n");
 
+   error = pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_L1SS,
+   2 * sizeof(u32));
+   if (error)
+   pci_err(dev, "unable to allocate suspend buffer for 
ASPM-L1SS\n");
+
pci_allocate_vc_save_buffers(dev);
 }
 
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fa12f7cbc1a0..8d2135f61e36 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -565,11 +565,15 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
 void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
+void pci_save_aspm_l1ss_state(struct pci_dev *dev);
+void pci_restore_aspm_l1ss_state(struct pci_dev *dev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
+static inline void pci_save_aspm_l1ss_state(struct pci_dev *dev) { }
+static inline void pci_restore_aspm_l1ss_state(struct pci_dev *dev) { }
 #endif
 
 #ifdef CONFIG_PCIE_ECRC
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 253c30cc1967..d965bbc563ed 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -742,6 +742,47 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state 
*link, u32 state)
PCI_L1SS_CTL1_L1SS_MASK, val);
 }
 
+void pci_save_aspm_l1ss_state(struct pci_dev *dev)
+{
+   struct pci_cap_saved_state *save_state;
+   int aspm_l1ss;
+   u32 *cap;
+
+   if (!pci_is_pcie(dev))
+   return;
+
+   aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!aspm_l1ss)
+   return;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state)
+   return;
+
+   cap = (u32 *)_state->cap.data[0];
+   pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, cap++);
+   pci_read_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, cap++);
+}
+
+void pci_restore_aspm_l1ss_state(struct pci_dev *dev)
+{
+   struct pci_cap_saved_state *save_state;
+   int aspm_l1ss;
+   u32 *cap;
+
+   if (!pci_is_pcie(dev))
+   return;
+
+   save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_L1SS);
+   aspm_l1ss = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_L1SS);
+   if (!save_state || !aspm_l1ss)
+   return;
+
+   cap = (u32 *)_state->cap.data[0];
+   pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL1, *cap++);
+   pci_write_config_dword(dev, aspm_l1ss + PCI_L1SS_CTL2, *cap++);
+}
+
 static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
 {
pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
-- 
2.17.1



[PATCH 1/3] PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit

2020-10-23 Thread Vidya Sagar
As per PCIe spec r5.0, sec 7.5.1.3.8 only 32-bit BAR registers are defined
for non-prefetchable memory and hence a warning should be reported when
the size of them go beyond 32-bits.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/of.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index ac24cd5439a9..5ea472ae22ac 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -556,6 +556,11 @@ static int pci_parse_request_of_pci_ranges(struct device 
*dev,
break;
case IORESOURCE_MEM:
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+
+   if (!(res->flags & IORESOURCE_PREFETCH))
+   if (upper_32_bits(resource_size(res)))
+   dev_warn(dev, "Memory resource size 
exceeds max for 32 bits\n");
+
break;
}
}
-- 
2.17.1



[PATCH 3/3] PCI: dwc: Add support to handle prefetchable memory mapping

2020-10-23 Thread Vidya Sagar
DWC sub-system currently doesn't differentiate between prefetchable and
non-prefetchable memory aperture entries in the 'ranges' property and
provides ATU mapping only for the first memory aperture entry out of all
the entries present. This was introduced by the
commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
Mapping for a memory apreture is required if its CPU address and the bus
address are different and the current mechanism works only if the memory
aperture which needs mapping happens to be the first entry. It doesn't
work either if the memory aperture that needs mapping is not the first
entry or if both prefetchable and non-prefetchable apertures need mapping.

This patch fixes this issue by differentiating between prefetchable and
non-prefetchable apertures in the 'ranges' property there by removing the
dependency on the order in which they are specified and adds support for
mapping prefetchable aperture using ATU region-3 if required.

Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")
Link: 
http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vid...@nvidia.com/

Signed-off-by: Vidya Sagar 
---
Changes from previous versions:
* Addressed Rob's comments and as part of that split the patch into three 
sub-patches
* Rewrote commit subject and description
* Addressed review comments from Lorenzo

 .../pci/controller/dwc/pcie-designware-host.c | 39 ---
 drivers/pci/controller/dwc/pcie-designware.h  |  1 +
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index 674f32db85ca..a1f319ccd816 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -529,9 +529,39 @@ static struct pci_ops dw_pcie_ops = {
.write = pci_generic_config_write,
 };
 
+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
+ struct resource_entry *win)
+{
+   struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+   /* Check for prefetchable memory aperture */
+   if (win->res->flags & IORESOURCE_PREFETCH) {
+   /* Number of view ports must at least be 4 to enable mapping */
+   if (pci->num_viewport < 4) {
+   dev_warn(pci->dev,
+"Insufficient ATU regions to map Prefetchable 
memory\n");
+   } else {
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX3,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+   } else { /* Non-prefetchable memory aperture */
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+}
+
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
u32 val, ctrl, num_ctrls;
+   struct resource_entry *win;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
/*
@@ -586,13 +616,10 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 * ATU, so we should not program the ATU here.
 */
if (pp->bridge->child_ops == _child_pcie_ops) {
-   struct resource_entry *entry =
-   resource_list_first_type(>bridge->windows, 
IORESOURCE_MEM);
+   resource_list_for_each_entry(win, >bridge->windows)
+   if (resource_type(win->res) == IORESOURCE_MEM)
+   dw_pcie_setup_mem_atu(pp, win);
 
-   dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, entry->res->start,
- entry->res->start - entry->offset,
- resource_size(entry->res));
if (pci->num_viewport > 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
  PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index e7f441441db2..21dd06831b50 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designwa

[PATCH 0/3] Add support to handle prefetchable memory

2020-10-23 Thread Vidya Sagar
This patch series adds support for configuring the DesignWare IP's ATU
region for prefetchable memory translations.
It first starts by flagging a warning if the size of non-prefetchable
aperture goes beyond 32-bit as PCIe spec doesn't allow it.
And then adds required support for programming the ATU to handle higher
(i.e. >4GB) sizes and then finally adds support for differentiating
between prefetchable and non-prefetchable regions and configuring one of
the ATU regions for prefetchable memory translations purpose.

Vidya Sagar (3):
  PCI: of: Warn if non-prefetchable memory aperture size is > 32-bit
  PCI: dwc: Add support to program ATU for >4GB memory aperture sizes
  PCI: dwc: Add support to handle prefetchable memory mapping

 .../pci/controller/dwc/pcie-designware-host.c | 39 ---
 drivers/pci/controller/dwc/pcie-designware.c  | 12 +++---
 drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
 drivers/pci/of.c  |  5 +++
 4 files changed, 48 insertions(+), 12 deletions(-)

-- 
2.17.1



[PATCH 2/3] PCI: dwc: Add support to program ATU for >4GB memory aperture sizes

2020-10-23 Thread Vidya Sagar
Add support to program the ATU to enable translations for >4GB sizes of
the prefetchable memory apertures.

Signed-off-by: Vidya Sagar 
---
 drivers/pci/controller/dwc/pcie-designware.c | 12 +++-
 drivers/pci/controller/dwc/pcie-designware.h |  3 ++-
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index c2dea8fc97c8..b5e438b70cd5 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -228,7 +228,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
 static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
-u32 size)
+u64 size)
 {
u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
@@ -245,8 +245,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
-type | PCIE_ATU_FUNC_NUM(func_no));
+   val = type | PCIE_ATU_FUNC_NUM(func_no);
+   val = upper_32_bits(size - 1) ?
+   val | PCIE_ATU_INCREASE_REGION_SIZE : val;
+   dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val);
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
 PCIE_ATU_ENABLE);
 
@@ -267,7 +269,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie 
*pci, u8 func_no,
 
 static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr,
-   u64 pci_addr, u32 size)
+   u64 pci_addr, u64 size)
 {
u32 retries, val;
 
@@ -311,7 +313,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie 
*pci, u8 func_no,
 }
 
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
-  u64 cpu_addr, u64 pci_addr, u32 size)
+  u64 cpu_addr, u64 pci_addr, u64 size)
 {
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h 
b/drivers/pci/controller/dwc/pcie-designware.h
index 9d2f511f13fa..e7f441441db2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -84,6 +84,7 @@
 #define PCIE_ATU_REGION_INDEX1 0x1
 #define PCIE_ATU_REGION_INDEX0 0x0
 #define PCIE_ATU_CR1   0x904
+#define PCIE_ATU_INCREASE_REGION_SIZE  BIT(13)
 #define PCIE_ATU_TYPE_MEM  0x0
 #define PCIE_ATU_TYPE_IO   0x2
 #define PCIE_ATU_TYPE_CFG0 0x4
@@ -295,7 +296,7 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci);
 int dw_pcie_wait_for_link(struct dw_pcie *pci);
 void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
   int type, u64 cpu_addr, u64 pci_addr,
-  u32 size);
+  u64 size);
 void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
  int type, u64 cpu_addr, u64 pci_addr,
  u32 size);
-- 
2.17.1



Re: [PATCH V2] PCI: dwc: Add support to handle prefetchable memory mapping

2020-10-23 Thread Vidya Sagar




On 10/23/2020 9:07 PM, Rob Herring wrote:

External email: Use caution opening links or attachments


On Fri, Oct 23, 2020 at 2:38 AM Vidya Sagar  wrote:




On 10/23/2020 12:38 AM, Rob Herring wrote:

External email: Use caution opening links or attachments


On Tue, Oct 20, 2020 at 2:59 PM Vidya Sagar  wrote:


DWC sub-system currently doesn't differentiate between prefetchable and
non-prefetchable memory aperture entries in the 'ranges' property and
provides ATU mapping only for the first memory aperture entry out of all
the entries present. This was introduced by the
commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
Mapping for a memory apreture is required if its CPU address and the bus
address are different and the current mechanism works only if the memory
aperture which needs mapping happens to be the first entry. It doesn't
work either if the memory aperture that needs mapping is not the first
entry or if both prefetchable and non-prefetchable apertures need mapping.


Well that's subtle...


This patch fixes this issue by differentiating between prefetchable and
non-prefetchable apertures in the 'ranges' property there by removing the
dependency on the order in which they are specified and adds support for
mapping prefetchable aperture using ATU region-3 if required.


Now you don't do any iATU entry for a 1:1 memory range which is a
change for pretty much every other platform. That means we leave the
PCI transaction config to the whims of how h/w designers hooked up the
sideband signals. I guess this is how Uniphier works as it only has 1
viewport...

I think the assignment should be in this order:
- config space
- non-prefetchable (IIRC, it's required)
- prefetchable
- i/o

Stopping assignment and warning if you run out of viewports. Looking
at the platforms, I think that would always work. There's only
uniphier and ls1012a where we run out. Those would still behave the
same.

As I see from the code this is how the current mapping is done

Region-0: [Fixed] Non-Prefetchable memory mapping

Region-1: [Shared] if the num of view ports <= 2
  Used for I/O by default but whenever config space is accessed,
it is programmed to generate config space, and once done, will program
it back for I/O generation. I'm not sure how they are synchonized when
two different entities are trying to access the config space as well as
the I/O at the same time.  I don't see any locking mechanism (or am I
missing something here??)


They aren't synchronized. We just get lucky that I/O and config
accesses aren't interleaved frequently. IMO, we should just not
support I/O space on those platforms. AIUI, almost everything doesn't
use I/O nowadays.


[Fixed] if the num of view ports > 2
  Used to generate configuration space accesses

Region-2: [Fixed] I/O accesses

Region-3: [Fixed] Prefetchable memory mapping (This patch is adding it)

I honestly think that an attempt to re-assing what region is used for
what purpose should go into a different patch.


Normally, I'd agree for a fix. If you want to fix it in a minimal way
such that we just setup the last memory region instead of the first,
then that's fine. But to implement the review feedback, you will
simply be adding support for multiple memory regions. The ATU doesn't
care about prefetchable or not. I think it will end up being a more
simple implementation if you just do the I/O region last and only if
you have an available.


I'll surely take it up next but would really like to hear from Jingoo 
and Gustavo if this breaks any legacy implementations. For now, I'll 
just program the ATU irrespective of 1:1 mapping as I want to get ToT 
working again on Tegra194.






I agree that I'm removing configuring an iATU region if it is for 1:1
memory mapping. What I heard from our HW designers is that it is the
default behavior of the Synopsys IP that if the CPU access falls in the
aperture owned by Synopsys IP and there is no iATU region mapped to
capture and generate any specific transaction for that address, then, by
default it generates a memory transaction over the PCIe bus.
It is also possible that some implementors might have chosen to alter
this behavior.


If we assume they haven't, that pretty much guarantees they did. :)


Ok. I'll address it in the next version




In any case, I can continue to have the iATU programming
done irrespective of whether it is for 1:1 mapping or not.






Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")
Link: 
http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vid...@nvidia.com/

Signed-off-by: Vidya Sagar 
---
V2:
* Rewrote commit subject and description
* Addressed review comments from Lorenzo

   .../pci/controller/dwc/pcie-designware-host.c | 42 ---
   drivers/pci/controller/dwc/pcie-designware.c  | 12 +++---
   drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
   3 files changed, 46 insertions

Re: [PATCH V2] PCI: dwc: Add support to handle prefetchable memory mapping

2020-10-23 Thread Vidya Sagar




On 10/23/2020 12:38 AM, Rob Herring wrote:

External email: Use caution opening links or attachments


On Tue, Oct 20, 2020 at 2:59 PM Vidya Sagar  wrote:


DWC sub-system currently doesn't differentiate between prefetchable and
non-prefetchable memory aperture entries in the 'ranges' property and
provides ATU mapping only for the first memory aperture entry out of all
the entries present. This was introduced by the
commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
Mapping for a memory apreture is required if its CPU address and the bus
address are different and the current mechanism works only if the memory
aperture which needs mapping happens to be the first entry. It doesn't
work either if the memory aperture that needs mapping is not the first
entry or if both prefetchable and non-prefetchable apertures need mapping.


Well that's subtle...


This patch fixes this issue by differentiating between prefetchable and
non-prefetchable apertures in the 'ranges' property there by removing the
dependency on the order in which they are specified and adds support for
mapping prefetchable aperture using ATU region-3 if required.


Now you don't do any iATU entry for a 1:1 memory range which is a
change for pretty much every other platform. That means we leave the
PCI transaction config to the whims of how h/w designers hooked up the
sideband signals. I guess this is how Uniphier works as it only has 1
viewport...

I think the assignment should be in this order:
- config space
- non-prefetchable (IIRC, it's required)
- prefetchable
- i/o

Stopping assignment and warning if you run out of viewports. Looking
at the platforms, I think that would always work. There's only
uniphier and ls1012a where we run out. Those would still behave the
same.

As I see from the code this is how the current mapping is done

Region-0: [Fixed] Non-Prefetchable memory mapping

Region-1: [Shared] if the num of view ports <= 2
Used for I/O by default but whenever config space is accessed, 
it is programmed to generate config space, and once done, will program 
it back for I/O generation. I'm not sure how they are synchonized when 
two different entities are trying to access the config space as well as 
the I/O at the same time.  I don't see any locking mechanism (or am I 
missing something here??)

  [Fixed] if the num of view ports > 2
Used to generate configuration space accesses

Region-2: [Fixed] I/O accesses

Region-3: [Fixed] Prefetchable memory mapping (This patch is adding it)

I honestly think that an attempt to re-assing what region is used for 
what purpose should go into a different patch.


I agree that I'm removing configuring an iATU region if it is for 1:1 
memory mapping. What I heard from our HW designers is that it is the 
default behavior of the Synopsys IP that if the CPU access falls in the 
aperture owned by Synopsys IP and there is no iATU region mapped to 
capture and generate any specific transaction for that address, then, by 
default it generates a memory transaction over the PCIe bus.
It is also possible that some implementors might have chosen to alter 
this behavior. In any case, I can continue to have the iATU programming 
done irrespective of whether it is for 1:1 mapping or not.







Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")
Link: 
http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vid...@nvidia.com/

Signed-off-by: Vidya Sagar 
---
V2:
* Rewrote commit subject and description
* Addressed review comments from Lorenzo

  .../pci/controller/dwc/pcie-designware-host.c | 42 ---
  drivers/pci/controller/dwc/pcie-designware.c  | 12 +++---
  drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
  3 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index db547ee6ff3a..dae6da39bb90 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -521,9 +521,42 @@ static struct pci_ops dw_pcie_ops = {
 .write = pci_generic_config_write,
  };

+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
+ struct resource_entry *win)
+{
+   struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+   /* Check for prefetchable memory aperture */
+   if (win->res->flags & IORESOURCE_PREFETCH && win->offset) {
+   /* Number of view ports must at least be 4 to enable mapping */
+   if (pci->num_viewport < 4) {
+   dev_warn(pci->dev,
+"Insufficient ATU regions to map Prefetchable 
memory\n");
+   } else {
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX3,
+

[PATCH V2] PCI: dwc: Add support to handle prefetchable memory mapping

2020-10-20 Thread Vidya Sagar
DWC sub-system currently doesn't differentiate between prefetchable and
non-prefetchable memory aperture entries in the 'ranges' property and
provides ATU mapping only for the first memory aperture entry out of all
the entries present. This was introduced by the
commit 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources").
Mapping for a memory apreture is required if its CPU address and the bus
address are different and the current mechanism works only if the memory
aperture which needs mapping happens to be the first entry. It doesn't
work either if the memory aperture that needs mapping is not the first
entry or if both prefetchable and non-prefetchable apertures need mapping.

This patch fixes this issue by differentiating between prefetchable and
non-prefetchable apertures in the 'ranges' property there by removing the
dependency on the order in which they are specified and adds support for
mapping prefetchable aperture using ATU region-3 if required.

Fixes: 0f71c60ffd26 ("PCI: dwc: Remove storing of PCI resources")
Link: 
http://patchwork.ozlabs.org/project/linux-pci/patch/20200513190855.23318-1-vid...@nvidia.com/

Signed-off-by: Vidya Sagar 
---
V2:
* Rewrote commit subject and description
* Addressed review comments from Lorenzo

 .../pci/controller/dwc/pcie-designware-host.c | 42 ---
 drivers/pci/controller/dwc/pcie-designware.c  | 12 +++---
 drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
 3 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index db547ee6ff3a..dae6da39bb90 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -521,9 +521,42 @@ static struct pci_ops dw_pcie_ops = {
.write = pci_generic_config_write,
 };
 
+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
+ struct resource_entry *win)
+{
+   struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+   /* Check for prefetchable memory aperture */
+   if (win->res->flags & IORESOURCE_PREFETCH && win->offset) {
+   /* Number of view ports must at least be 4 to enable mapping */
+   if (pci->num_viewport < 4) {
+   dev_warn(pci->dev,
+"Insufficient ATU regions to map Prefetchable 
memory\n");
+   } else {
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX3,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+   } else if (win->offset) { /* Non-prefetchable memory aperture */
+   if (upper_32_bits(resource_size(win->res)))
+   dev_warn(pci->dev,
+"Memory resource size exceeds max for 32 
bits\n");
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+}
+
 void dw_pcie_setup_rc(struct pcie_port *pp)
 {
u32 val, ctrl, num_ctrls;
+   struct resource_entry *win;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 
/*
@@ -578,13 +611,10 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 * ATU, so we should not program the ATU here.
 */
if (pp->bridge->child_ops == _child_pcie_ops) {
-   struct resource_entry *entry =
-   resource_list_first_type(>bridge->windows, 
IORESOURCE_MEM);
+   resource_list_for_each_entry(win, >bridge->windows)
+   if (resource_type(win->res) == IORESOURCE_MEM)
+   dw_pcie_setup_mem_atu(pp, win);
 
-   dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, entry->res->start,
- entry->res->start - entry->offset,
- resource_size(entry->res));
if (pci->num_viewport > 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
  PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pc

Re: [PATCH] PCI: dwc: Use ATU regions to map memory regions

2020-10-20 Thread Vidya Sagar




On 10/20/2020 6:50 PM, Lorenzo Pieralisi wrote:

External email: Use caution opening links or attachments


On Mon, Oct 19, 2020 at 11:21:54AM +0530, Vidya Sagar wrote:

Hi Lorenzo, Rob, Gustavo,
Could you please review this change?


Next cycle - we are in the middle of the merge window and I am not
queueing any more patches.


Thanks for the update.
FWIW, PCIe is broken on Tegra194 with Rob's patches (which got accepted 
already) and without the current patch.


Thanks,
Vidya Sagar



Thanks,
Lorenzo


Thanks,
Vidya Sagar

On 10/5/2020 5:43 PM, Vidya Sagar wrote:

Use ATU region-3 and region-0 to setup mapping for prefetchable and
non-prefetchable memory regions respectively only if their respective CPU
and bus addresses are different.

Signed-off-by: Vidya Sagar 
---
   .../pci/controller/dwc/pcie-designware-host.c | 44 ---
   drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
   drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
   3 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index 317ff512f8df..cefde8e813e9 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -515,9 +515,40 @@ static struct pci_ops dw_pcie_ops = {
 .write = pci_generic_config_write,
   };
+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,
+ struct resource_entry *win)
+{
+   struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+   if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
+   win->offset) {
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX3,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   } else if (win->res->flags & IORESOURCE_PREFETCH &&
+  pci->num_viewport < 4) {
+   dev_warn(pci->dev,
+"Insufficient ATU regions to map Prefetchable memory\n");
+   } else if (win->offset) {
+   if (upper_32_bits(resource_size(win->res)))
+   dev_warn(pci->dev,
+"Memory resource size exceeds max for 32 bits\n");
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+}
+
   void dw_pcie_setup_rc(struct pcie_port *pp)
   {
 u32 val, ctrl, num_ctrls;
+   struct resource_entry *win;
 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
 /*
@@ -572,13 +603,14 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
  * ATU, so we should not program the ATU here.
  */
 if (pp->bridge->child_ops == _child_pcie_ops) {
-   struct resource_entry *entry =
-   resource_list_first_type(>bridge->windows, 
IORESOURCE_MEM);
+   resource_list_for_each_entry(win, >bridge->windows) {
+   switch (resource_type(win->res)) {
+   case IORESOURCE_MEM:
+   dw_pcie_setup_mem_atu(pp, win);
+   break;
+   }
+   }
-   dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
- PCIE_ATU_TYPE_MEM, entry->res->start,
- entry->res->start - entry->offset,
- resource_size(entry->res));
 if (pci->num_viewport > 2)
 dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
   PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index 3c1f17c78241..6033689abb15 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
   static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
  int index, int type,
  u64 cpu_addr, u64 pci_addr,
-u32 size)
+u64 size)
   {
 u32 retries, val;
 u64 limit_addr = cpu_addr + size - 1;
@@ -244,8 +244,10 @@ static void dw_pcie_prog_ou

Re: [PATCH] PCI: dwc: Use ATU regions to map memory regions

2020-10-18 Thread Vidya Sagar

Hi Lorenzo, Rob, Gustavo,
Could you please review this change?

Thanks,
Vidya Sagar

On 10/5/2020 5:43 PM, Vidya Sagar wrote:

Use ATU region-3 and region-0 to setup mapping for prefetchable and
non-prefetchable memory regions respectively only if their respective CPU
and bus addresses are different.

Signed-off-by: Vidya Sagar 
---
  .../pci/controller/dwc/pcie-designware-host.c | 44 ---
  drivers/pci/controller/dwc/pcie-designware.c  | 12 ++---
  drivers/pci/controller/dwc/pcie-designware.h  |  4 +-
  3 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c
index 317ff512f8df..cefde8e813e9 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -515,9 +515,40 @@ static struct pci_ops dw_pcie_ops = {
.write = pci_generic_config_write,
  };
  
+static void dw_pcie_setup_mem_atu(struct pcie_port *pp,

+ struct resource_entry *win)
+{
+   struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+   if (win->res->flags & IORESOURCE_PREFETCH && pci->num_viewport >= 4 &&
+   win->offset) {
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX3,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   } else if (win->res->flags & IORESOURCE_PREFETCH &&
+  pci->num_viewport < 4) {
+   dev_warn(pci->dev,
+"Insufficient ATU regions to map Prefetchable 
memory\n");
+   } else if (win->offset) {
+   if (upper_32_bits(resource_size(win->res)))
+   dev_warn(pci->dev,
+"Memory resource size exceeds max for 32 
bits\n");
+   dw_pcie_prog_outbound_atu(pci,
+ PCIE_ATU_REGION_INDEX0,
+ PCIE_ATU_TYPE_MEM,
+ win->res->start,
+ win->res->start - win->offset,
+ resource_size(win->res));
+   }
+}
+
  void dw_pcie_setup_rc(struct pcie_port *pp)
  {
u32 val, ctrl, num_ctrls;
+   struct resource_entry *win;
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
  
  	/*

@@ -572,13 +603,14 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
 * ATU, so we should not program the ATU here.
 */
if (pp->bridge->child_ops == _child_pcie_ops) {
-   struct resource_entry *entry =
-   resource_list_first_type(>bridge->windows, 
IORESOURCE_MEM);
+   resource_list_for_each_entry(win, >bridge->windows) {
+   switch (resource_type(win->res)) {
+   case IORESOURCE_MEM:
+   dw_pcie_setup_mem_atu(pp, win);
+   break;
+   }
+   }
  
-		dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,

- PCIE_ATU_TYPE_MEM, entry->res->start,
- entry->res->start - entry->offset,
- resource_size(entry->res));
if (pci->num_viewport > 2)
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
  PCIE_ATU_TYPE_IO, pp->io_base,
diff --git a/drivers/pci/controller/dwc/pcie-designware.c 
b/drivers/pci/controller/dwc/pcie-designware.c
index 3c1f17c78241..6033689abb15 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -227,7 +227,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, 
u32 index, u32 reg,
  static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
 int index, int type,
 u64 cpu_addr, u64 pci_addr,
-u32 size)
+u64 size)
  {
u32 retries, val;
u64 limit_addr = cpu_addr + size - 1;
@@ -244,8 +244,10 @@ static void dw_pcie_prog_outbound_atu_unroll(struct 
dw_pcie *pci, u8 func_no,
 lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
 upper_32_bits(pci_addr));
-   dw_p

Re: [PATCH v7 2/2] PCI: dwc: Fix MSI page leakage in suspend/resume

2020-10-12 Thread Vidya Sagar




On 10/12/2020 5:07 PM, Robin Murphy wrote:

External email: Use caution opening links or attachments


On 2020-10-09 08:55, Jisheng Zhang wrote:

Currently, dw_pcie_msi_init() allocates and maps page for msi, then
program the PCIE_MSI_ADDR_LO and PCIE_MSI_ADDR_HI. The Root Complex
may lose power during suspend-to-RAM, so when we resume, we want to
redo the latter but not the former. If designware based driver (for
example, pcie-tegra194.c) calls dw_pcie_msi_init() in resume path, the
msi page will be leaked.

As pointed out by Rob and Ard, there's no need to allocate a page for
the MSI address, we could use an address in the driver data.

To avoid map the MSI msg again during resume, we move the map MSI msg
from dw_pcie_msi_init() to dw_pcie_host_init().


You should move the unmap there as well. As soon as you know what the
relevant address would be if you *were* to do DMA to this location, then
the exercise is complete. Leaving it mapped for the lifetime of the
device in order to do not-DMA to it seems questionable (and represents
technically incorrect API usage without at least a sync_for_cpu call
before any other access to the data).

Another point of note is that using streaming DMA mappings at all is a
bit fragile (regardless of this change). If the host controller itself
has a limited DMA mask relative to physical memory (which integrators
still seem to keep doing...) then you could end up punching your MSI
hole right in the middle of the SWIOTLB bounce buffer, where it's then
almost *guaranteed* to interfere with real DMA :(
Agree with Robin. Since the MSI page is going to be locked till 
shutdown/reboot, wouldn't it make sense to use dma_alloc_coherent() API?
Also, shouldn't we call dma_set_mask() to limit the address to only 
32-bits so as to enable MSI for even those legacy PCIe devices with only 
32-bit MSI capability?


- Vidya Sagar



If no DWC users have that problem and the current code is working well
enough, then I see little reason not to make this partucular change to
tidy up the implementation, just bear in mind that there's always the
possibility of having to come back and change it yet again in future to
make it more robust. I had it in mind that this trick was done with a
coherent DMA allocation, which would be safe from addressing problems
but would need to be kept around for the lifetime of the device, but
maybe that was a different driver :/

Robin.


Suggested-by: Rob Herring 
Signed-off-by: Jisheng Zhang 
Reviewed-by: Rob Herring 
---
  drivers/pci/controller/dwc/pci-dra7xx.c   | 18 +-
  .../pci/controller/dwc/pcie-designware-host.c | 33 ++-
  drivers/pci/controller/dwc/pcie-designware.h  |  2 +-
  3 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c 
b/drivers/pci/controller/dwc/pci-dra7xx.c

index 8f0b6d644e4b..6d012d2b1e90 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -466,7 +466,9 @@ static struct irq_chip 
dra7xx_pci_msi_bottom_irq_chip = {

  static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
  {
  struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
  u32 ctrl, num_ctrls;
+ int ret;

  pp->msi_irq_chip = _pci_msi_bottom_irq_chip;

@@ -482,7 +484,21 @@ static int dra7xx_pcie_msi_host_init(struct 
pcie_port *pp)

  ~0);
  }

- return dw_pcie_allocate_domains(pp);
+ ret = dw_pcie_allocate_domains(pp);
+ if (ret)
+ return ret;
+
+ pp->msi_data = dma_map_single_attrs(dev, >msi_msg,
+    sizeof(pp->msi_msg),
+    DMA_FROM_DEVICE,
+    DMA_ATTR_SKIP_CPU_SYNC);
+ ret = dma_mapping_error(dev, pp->msi_data);
+ if (ret) {
+ dev_err(dev, "Failed to map MSI data\n");
+ pp->msi_data = 0;
+ dw_pcie_free_msi(pp);
+ }
+ return ret;
  }

  static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c 
b/drivers/pci/controller/dwc/pcie-designware-host.c

index d3e9ea11ce9e..d02c7e74738d 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -266,30 +266,23 @@ void dw_pcie_free_msi(struct pcie_port *pp)
  irq_domain_remove(pp->msi_domain);
  irq_domain_remove(pp->irq_domain);

- if (pp->msi_page)
- __free_page(pp->msi_page);
+ if (pp->msi_data) {
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct device *dev = pci->dev;
+
+ dma_unmap_single_attrs(dev, pp->msi_data, 
sizeof(pp->msi_msg),
+    DMA_FROM_DEVICE, 
DMA_ATTR_SKIP_CPU_SYNC);

+ }
  }

  void dw_pcie_msi_init(struct pcie_port *pp

Re: [PATCH v2 5/5] PCI: dwc: Move dw_pcie_msi_init() from each users to designware host

2020-10-07 Thread Vidya Sagar




On 9/24/2020 4:37 PM, Jisheng Zhang wrote:

External email: Use caution opening links or attachments


Currently, dw_pcie_msi_init() allocates and maps page for msi, then
program the PCIE_MSI_ADDR_LO and PCIE_MSI_ADDR_HI. The Root Complex
may lose power during suspend-to-RAM, so when we resume, we want to
redo the latter but not the former. If designware based driver (for
example, pcie-tegra194.c) calls dw_pcie_msi_init() in resume path, the
previous msi page will be leaked. From another side, except
pci-dra7xx.c we can move the dw_pcie_msi_init() from each users to
designware host, I.E move the msi page allocation and mapping to
dw_pcie_host_init() and move the PCIE_MSI_ADDR_* programming to
dw_pcie_setup_rc(). After this moving, we solve the msi page leakage
as well.

Signed-off-by: Jisheng Zhang 
---
  drivers/pci/controller/dwc/pci-dra7xx.c   |  1 +
  drivers/pci/controller/dwc/pci-exynos.c   |  2 --
  drivers/pci/controller/dwc/pci-imx6.c |  3 ---
  drivers/pci/controller/dwc/pci-meson.c|  8 ---
  drivers/pci/controller/dwc/pcie-artpec6.c | 10 
  .../pci/controller/dwc/pcie-designware-host.c | 24 ---
  .../pci/controller/dwc/pcie-designware-plat.c |  3 ---
  drivers/pci/controller/dwc/pcie-designware.h  |  5 
  drivers/pci/controller/dwc/pcie-histb.c   |  3 ---
  drivers/pci/controller/dwc/pcie-kirin.c   |  3 ---
  drivers/pci/controller/dwc/pcie-qcom.c|  3 ---
  drivers/pci/controller/dwc/pcie-spear13xx.c   |  1 -
  drivers/pci/controller/dwc/pcie-tegra194.c|  2 --
  drivers/pci/controller/dwc/pcie-uniphier.c|  9 +--
  14 files changed, 22 insertions(+), 55 deletions(-)

diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c 
b/drivers/pci/controller/dwc/pci-dra7xx.c
index dc387724cf08..d8b74389e353 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -210,6 +210,7 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
 dra7xx_pcie_establish_link(pci);
 dw_pcie_wait_for_link(pci);
 dw_pcie_msi_init(pp);
+   dw_pcie_msi_config(pp);
 dra7xx_pcie_enable_interrupts(dra7xx);

 return 0;
diff --git a/drivers/pci/controller/dwc/pci-exynos.c 
b/drivers/pci/controller/dwc/pci-exynos.c
index 8d82c43ae299..9cca0ce79777 100644
--- a/drivers/pci/controller/dwc/pci-exynos.c
+++ b/drivers/pci/controller/dwc/pci-exynos.c
@@ -298,8 +298,6 @@ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
 struct pcie_port *pp = >pp;
 u32 val;

-   dw_pcie_msi_init(pp);
-
 /* enable MSI interrupt */
 val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
 val |= IRQ_MSI_ENABLE;
diff --git a/drivers/pci/controller/dwc/pci-imx6.c 
b/drivers/pci/controller/dwc/pci-imx6.c
index 5fef2613b223..dba6e351e3df 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -848,9 +848,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
 dw_pcie_setup_rc(pp);
 imx6_pcie_establish_link(imx6_pcie);

-   if (IS_ENABLED(CONFIG_PCI_MSI))
-   dw_pcie_msi_init(pp);
-
 return 0;
  }

diff --git a/drivers/pci/controller/dwc/pci-meson.c 
b/drivers/pci/controller/dwc/pci-meson.c
index 4f183b96afbb..cd0d9dd8dd61 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -377,12 +377,6 @@ static int meson_pcie_establish_link(struct meson_pcie *mp)
 return dw_pcie_wait_for_link(pci);
  }

-static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
-{
-   if (IS_ENABLED(CONFIG_PCI_MSI))
-   dw_pcie_msi_init(>pci.pp);
-}
-
  static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
   u32 *val)
  {
@@ -467,8 +461,6 @@ static int meson_pcie_host_init(struct pcie_port *pp)
 if (ret)
 return ret;

-   meson_pcie_enable_interrupts(mp);
-
 return 0;
  }

diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c 
b/drivers/pci/controller/dwc/pcie-artpec6.c
index 97d50bb50f06..af1e6bb28e7a 100644
--- a/drivers/pci/controller/dwc/pcie-artpec6.c
+++ b/drivers/pci/controller/dwc/pcie-artpec6.c
@@ -346,15 +346,6 @@ static void artpec6_pcie_deassert_core_reset(struct 
artpec6_pcie *artpec6_pcie)
 usleep_range(100, 200);
  }

-static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
-{
-   struct dw_pcie *pci = artpec6_pcie->pci;
-   struct pcie_port *pp = >pp;
-
-   if (IS_ENABLED(CONFIG_PCI_MSI))
-   dw_pcie_msi_init(pp);
-}
-
  static int artpec6_pcie_host_init(struct pcie_port *pp)
  {
 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -368,7 +359,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
 dw_pcie_setup_rc(pp);
 artpec6_pcie_establish_link(pci);
 dw_pcie_wait_for_link(pci);
-   

  1   2   3   4   5   6   >