linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bjorn Helgaas <helgaas@kernel.org>
To: "Pali Rohár" <pali@kernel.org>
Cc: "Lorenzo Pieralisi" <lorenzo.pieralisi@arm.com>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Rob Herring" <robh+dt@kernel.org>,
	"Andrew Lunn" <andrew@lunn.ch>,
	"Thomas Petazzoni" <thomas.petazzoni@bootlin.com>,
	"Krzysztof Wilczyński" <kw@linux.com>,
	"Marek Behún" <kabel@kernel.org>,
	"Russell King" <rmk+kernel@armlinux.org.uk>,
	linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 4/4] PCI: mvebu: Add support for sending Set_Slot_Power_Limit message
Date: Thu, 24 Mar 2022 12:15:01 -0500	[thread overview]
Message-ID: <20220324171501.GA1460207@bhelgaas> (raw)
In-Reply-To: <20220302145733.12606-5-pali@kernel.org>

On Wed, Mar 02, 2022 at 03:57:33PM +0100, Pali Rohár wrote:
> If DT supplies the 'slot-power-limit-milliwatt' property, program
> the value in the Slot Power Limit in the Slot Capabilities register
> and program the Root Port to send a Set_Slot_Power_Limit Message
> when the Link transitions to DL_Up.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>

I didn't review this carefully but have no objection.

> ---
> Changes in v2:
> * Fix handling of slot power limit with scale x1.0 (0x00 value)
> * Use FIELD_PREP instead of _SHIFT macros
> * Changed commit message to Bjorn's suggestion
> * Changed comments in the code to match PCIe spec
> * Preserve user settings of PCI_EXP_SLTCTL_ASPL_DISABLE bit
> ---
>  drivers/pci/controller/pci-mvebu.c | 96 ++++++++++++++++++++++++++++--
>  1 file changed, 91 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
> index a75d2b9196f9..26ae7c29fece 100644
> --- a/drivers/pci/controller/pci-mvebu.c
> +++ b/drivers/pci/controller/pci-mvebu.c
> @@ -8,6 +8,7 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/pci.h>
> +#include <linux/bitfield.h>
>  #include <linux/clk.h>
>  #include <linux/delay.h>
>  #include <linux/gpio.h>
> @@ -66,6 +67,12 @@
>  #define  PCIE_STAT_BUS                  0xff00
>  #define  PCIE_STAT_DEV                  0x1f0000
>  #define  PCIE_STAT_LINK_DOWN		BIT(0)
> +#define PCIE_SSPL_OFF		0x1a0c
> +#define  PCIE_SSPL_VALUE_SHIFT		0
> +#define  PCIE_SSPL_VALUE_MASK		GENMASK(7, 0)
> +#define  PCIE_SSPL_SCALE_SHIFT		8
> +#define  PCIE_SSPL_SCALE_MASK		GENMASK(9, 8)
> +#define  PCIE_SSPL_ENABLE		BIT(16)
>  #define PCIE_RC_RTSTA		0x1a14
>  #define PCIE_DEBUG_CTRL         0x1a60
>  #define  PCIE_DEBUG_SOFT_RESET		BIT(20)
> @@ -111,6 +118,8 @@ struct mvebu_pcie_port {
>  	struct mvebu_pcie_window iowin;
>  	u32 saved_pcie_stat;
>  	struct resource regs;
> +	u8 slot_power_limit_value;
> +	u8 slot_power_limit_scale;
>  	struct irq_domain *intx_irq_domain;
>  	raw_spinlock_t irq_lock;
>  	int intx_irq;
> @@ -239,7 +248,7 @@ static void mvebu_pcie_setup_wins(struct mvebu_pcie_port *port)
>  
>  static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
>  {
> -	u32 ctrl, lnkcap, cmd, dev_rev, unmask;
> +	u32 ctrl, lnkcap, cmd, dev_rev, unmask, sspl;
>  
>  	/* Setup PCIe controller to Root Complex mode. */
>  	ctrl = mvebu_readl(port, PCIE_CTRL_OFF);
> @@ -292,6 +301,20 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port)
>  	/* Point PCIe unit MBUS decode windows to DRAM space. */
>  	mvebu_pcie_setup_wins(port);
>  
> +	/*
> +	 * Program Root Port to automatically send Set_Slot_Power_Limit
> +	 * PCIe Message when changing status from Dl_Down to Dl_Up and valid
> +	 * slot power limit was specified.
> +	 */
> +	sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> +	sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
> +	if (port->slot_power_limit_value) {
> +		sspl |= port->slot_power_limit_value << PCIE_SSPL_VALUE_SHIFT;
> +		sspl |= port->slot_power_limit_scale << PCIE_SSPL_SCALE_SHIFT;
> +		sspl |= PCIE_SSPL_ENABLE;
> +	}
> +	mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> +
>  	/* Mask all interrupt sources. */
>  	mvebu_writel(port, ~PCIE_INT_ALL_MASK, PCIE_INT_UNMASK_OFF);
>  
> @@ -628,9 +651,23 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
>  			  (PCI_EXP_LNKSTA_DLLLA << 16) : 0);
>  		break;
>  
> -	case PCI_EXP_SLTCTL:
> -		*value = PCI_EXP_SLTSTA_PDS << 16;
> +	case PCI_EXP_SLTCTL: {
> +		u16 slotsta = le16_to_cpu(bridge->pcie_conf.slotsta);
> +		u32 val = 0;
> +		/*
> +		 * When slot power limit was not specified in DT then
> +		 * ASPL_DISABLE bit is stored only in emulated config space.
> +		 * Otherwise reflect status of PCIE_SSPL_ENABLE bit in HW.
> +		 */
> +		if (!port->slot_power_limit_value)
> +			val |= slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE;
> +		else if (!(mvebu_readl(port, PCIE_SSPL_OFF) & PCIE_SSPL_ENABLE))
> +			val |= PCI_EXP_SLTCTL_ASPL_DISABLE;
> +		/* This callback is 32-bit and in high bits is slot status. */
> +		val |= slotsta << 16;
> +		*value = val;
>  		break;
> +	}
>  
>  	case PCI_EXP_RTSTA:
>  		*value = mvebu_readl(port, PCIE_RC_RTSTA);
> @@ -774,6 +811,22 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
>  		mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
>  		break;
>  
> +	case PCI_EXP_SLTCTL:
> +		/*
> +		 * Allow to change PCIE_SSPL_ENABLE bit only when slot power
> +		 * limit was specified in DT and configured into HW.
> +		 */
> +		if ((mask & PCI_EXP_SLTCTL_ASPL_DISABLE) &&
> +		    port->slot_power_limit_value) {
> +			u32 sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> +			if (new & PCI_EXP_SLTCTL_ASPL_DISABLE)
> +				sspl &= ~PCIE_SSPL_ENABLE;
> +			else
> +				sspl |= PCIE_SSPL_ENABLE;
> +			mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> +		}
> +		break;
> +
>  	case PCI_EXP_RTSTA:
>  		/*
>  		 * PME Status bit in Root Status Register (PCIE_RC_RTSTA)
> @@ -868,8 +921,26 @@ static int mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
>  	/*
>  	 * Older mvebu hardware provides PCIe Capability structure only in
>  	 * version 1. New hardware provides it in version 2.
> +	 * Enable slot support which is emulated.
>  	 */
> -	bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver);
> +	bridge->pcie_conf.cap = cpu_to_le16(pcie_cap_ver | PCI_EXP_FLAGS_SLOT);
> +
> +	/*
> +	 * Set Presence Detect State bit permanently as there is no support for
> +	 * unplugging PCIe card from the slot. Assume that PCIe card is always
> +	 * connected in slot.
> +	 *
> +	 * Set physical slot number to port+1 as mvebu ports are indexed from
> +	 * zero and zero value is reserved for ports within the same silicon
> +	 * as Root Port which is not mvebu case.
> +	 *
> +	 * Also set correct slot power limit.
> +	 */
> +	bridge->pcie_conf.slotcap = cpu_to_le32(
> +		FIELD_PREP(PCI_EXP_SLTCAP_SPLV, port->slot_power_limit_value) |
> +		FIELD_PREP(PCI_EXP_SLTCAP_SPLS, port->slot_power_limit_scale) |
> +		FIELD_PREP(PCI_EXP_SLTCAP_PSN, port->port+1));
> +	bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
>  
>  	bridge->subsystem_vendor_id = ssdev_id & 0xffff;
>  	bridge->subsystem_id = ssdev_id >> 16;
> @@ -1191,6 +1262,7 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
>  {
>  	struct device *dev = &pcie->pdev->dev;
>  	enum of_gpio_flags flags;
> +	u32 slot_power_limit;
>  	int reset_gpio, ret;
>  	u32 num_lanes;
>  
> @@ -1291,6 +1363,15 @@ static int mvebu_pcie_parse_port(struct mvebu_pcie *pcie,
>  		port->reset_gpio = gpio_to_desc(reset_gpio);
>  	}
>  
> +	slot_power_limit = of_pci_get_slot_power_limit(child,
> +				&port->slot_power_limit_value,
> +				&port->slot_power_limit_scale);
> +	if (slot_power_limit)
> +		dev_info(dev, "%s: Slot power limit %u.%uW\n",
> +			 port->name,
> +			 slot_power_limit / 1000,
> +			 (slot_power_limit / 100) % 10);
> +
>  	port->clk = of_clk_get_by_name(child, NULL);
>  	if (IS_ERR(port->clk)) {
>  		dev_err(dev, "%s: cannot get clock\n", port->name);
> @@ -1587,7 +1668,7 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
>  {
>  	struct mvebu_pcie *pcie = platform_get_drvdata(pdev);
>  	struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
> -	u32 cmd;
> +	u32 cmd, sspl;
>  	int i;
>  
>  	/* Remove PCI bus with all devices. */
> @@ -1624,6 +1705,11 @@ static int mvebu_pcie_remove(struct platform_device *pdev)
>  		/* Free config space for emulated root bridge. */
>  		pci_bridge_emul_cleanup(&port->bridge);
>  
> +		/* Disable sending Set_Slot_Power_Limit PCIe Message. */
> +		sspl = mvebu_readl(port, PCIE_SSPL_OFF);
> +		sspl &= ~(PCIE_SSPL_VALUE_MASK | PCIE_SSPL_SCALE_MASK | PCIE_SSPL_ENABLE);
> +		mvebu_writel(port, sspl, PCIE_SSPL_OFF);
> +
>  		/* Disable and clear BARs and windows. */
>  		mvebu_pcie_disable_wins(port);
>  
> -- 
> 2.20.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2022-03-24 17:15 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-02 14:57 [PATCH v2 0/4] PCI: mvebu: Slot support Pali Rohár
2022-03-02 14:57 ` [PATCH v2 1/4] PCI: Add PCI_EXP_SLTCTL_ASPL_DISABLE macro Pali Rohár
2022-03-02 14:57 ` [PATCH v2 2/4] dt-bindings: Add 'slot-power-limit-milliwatt' PCIe port property Pali Rohár
2022-03-24 20:47   ` Rob Herring
2022-03-02 14:57 ` [PATCH v2 3/4] PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property Pali Rohár
2022-03-24 17:13   ` Bjorn Helgaas
2022-03-25  9:20     ` Pali Rohár
2022-03-02 14:57 ` [PATCH v2 4/4] PCI: mvebu: Add support for sending Set_Slot_Power_Limit message Pali Rohár
2022-03-24 17:15   ` Bjorn Helgaas [this message]
2022-03-24 20:50   ` Rob Herring
2022-03-08 11:38 ` [PATCH v2 0/4] PCI: mvebu: Slot support Pali Rohár
2022-03-21 18:29   ` Pali Rohár
2022-03-24 17:12     ` Bjorn Helgaas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220324171501.GA1460207@bhelgaas \
    --to=helgaas@kernel.org \
    --cc=andrew@lunn.ch \
    --cc=bhelgaas@google.com \
    --cc=kabel@kernel.org \
    --cc=kw@linux.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lorenzo.pieralisi@arm.com \
    --cc=pali@kernel.org \
    --cc=rmk+kernel@armlinux.org.uk \
    --cc=robh+dt@kernel.org \
    --cc=thomas.petazzoni@bootlin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).