Re: [RFC PATCH 2/3] PCI: aardvark: Add support for sending Set_Slot_Power_Limit message

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tuesday 24 August 2021 10:58:31 Rob Herring wrote:
> On Fri, Aug 20, 2021 at 06:00:22PM +0200, Pali Rohár wrote:
> > According to PCIe Base specification 3.0, when transitioning from a
> > non-DL_Up Status to a DL_Up Status, the Port must initiate the
> > transmission of a Set_Slot_Power_Limit Message to the other component
> > on the Link to convey the value programmed in the Slot Power Limit
> > Scale and Value fields of the Slot Capabilities register. This
> > Transmission is optional if the Slot Capabilities register has not
> > yet been initialized.
> > 
> > As PCIe Root Bridge is emulated by kernel emulate readback of Slot Power
> > Limit Scale and Value bits in Slot Capabilities register.
> > 
> > Also send that Set_Slot_Power_Limit message via Message Generation Control
> > Register in Link Up handler when link changes from down to up state and
> > slot power limit value was defined.
> > 
> > Slot power limit value is read from DT property 'slot-power-limit' which
> > value is in mW unit. When this DT property is not specified then it is
> > treated as "Slot Capabilities register has not yet been initialized".
> > 
> > Signed-off-by: Pali Rohár <pali@xxxxxxxxxx>
> > ---
> >  .../devicetree/bindings/pci/aardvark-pci.txt  |  2 +
> >  drivers/pci/controller/pci-aardvark.c         | 66 ++++++++++++++++++-
> >  2 files changed, 67 insertions(+), 1 deletion(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/pci/aardvark-pci.txt b/Documentation/devicetree/bindings/pci/aardvark-pci.txt
> > index 2b8ca920a7fa..bb658f261db0 100644
> > --- a/Documentation/devicetree/bindings/pci/aardvark-pci.txt
> > +++ b/Documentation/devicetree/bindings/pci/aardvark-pci.txt
> > @@ -20,6 +20,7 @@ contain the following properties:
> >     define the mapping of the PCIe interface to interrupt numbers.
> >   - bus-range: PCI bus numbers covered
> >   - phys: the PCIe PHY handle
> > + - slot-power-limit: see pci.txt
> >   - max-link-speed: see pci.txt
> >   - reset-gpios: see pci.txt
> >  
> > @@ -52,6 +53,7 @@ Example:
> >  				<0 0 0 3 &pcie_intc 2>,
> >  				<0 0 0 4 &pcie_intc 3>;
> >  		phys = <&comphy1 0>;
> > +		slot-power-limit: <10000>;
> >  		pcie_intc: interrupt-controller {
> >  			interrupt-controller;
> >  			#interrupt-cells = <1>;
> > diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
> > index f94898f6072f..cf704c199c15 100644
> > --- a/drivers/pci/controller/pci-aardvark.c
> > +++ b/drivers/pci/controller/pci-aardvark.c
> > @@ -166,6 +166,11 @@
> >  #define VENDOR_ID_REG				(LMI_BASE_ADDR + 0x44)
> >  #define DEBUG_MUX_CTRL_REG			(LMI_BASE_ADDR + 0x208)
> >  #define     DIS_ORD_CHK				BIT(30)
> > +#define PME_MSG_GEN_CTRL			(LMI_BASE_ADDR + 0x220)
> > +#define     SEND_SET_SLOT_POWER_LIMIT		BIT(13)
> > +#define     SEND_PME_TURN_OFF			BIT(14)
> > +#define     SLOT_POWER_LIMIT_DATA_SHIFT		16
> > +#define     SLOT_POWER_LIMIT_DATA_MASK		GENMASK(25, 16)
> >  
> >  /* PCIe core controller registers */
> >  #define CTRL_CORE_BASE_ADDR			0x18000
> > @@ -267,6 +272,7 @@ static bool advk_pcie_link_up(struct advk_pcie *pcie)
> >  {
> >  	u32 val, ltssm_state;
> >  	u16 slotsta, slotctl;
> > +	u32 slotpwr;
> >  	bool link_up;
> >  
> >  	val = advk_readl(pcie, CFG_REG);
> > @@ -277,7 +283,25 @@ static bool advk_pcie_link_up(struct advk_pcie *pcie)
> >  		pcie->link_up = true;
> >  		slotsta = le16_to_cpu(pcie->bridge.pcie_conf.slotsta);
> >  		slotctl = le16_to_cpu(pcie->bridge.pcie_conf.slotctl);
> > +		slotpwr = (le32_to_cpu(pcie->bridge.pcie_conf.slotcap) &
> > +			   (PCI_EXP_SLTCAP_SPLV | PCI_EXP_SLTCAP_SPLS)) >> 7;
> >  		pcie->bridge.pcie_conf.slotsta = cpu_to_le16(slotsta | PCI_EXP_SLTSTA_DLLSC);
> > +		if (!(slotctl & PCI_EXP_SLTCTL_ASPL_DISABLE) && slotpwr) {
> > +			/*
> > +			 * According to PCIe Base specification 3.0, when transitioning from a
> > +			 * non-DL_Up Status to a DL_Up Status, the Port must initiate the
> > +			 * transmission of a Set_Slot_Power_Limit Message to the other component
> > +			 * on the Link to convey the value programmed in the Slot Power Limit
> > +			 * Scale and Value fields of the Slot Capabilities register. This
> > +			 * Transmission is optional if the Slot Capabilities register has not
> > +			 * yet been initialized.
> > +			 */
> > +			val = advk_readl(pcie, PME_MSG_GEN_CTRL);
> > +			val &= ~SLOT_POWER_LIMIT_DATA_MASK;
> > +			val |= slotpwr << SLOT_POWER_LIMIT_DATA_SHIFT;
> > +			val |= SEND_SET_SLOT_POWER_LIMIT;
> > +			advk_writel(pcie, val, PME_MSG_GEN_CTRL);
> > +		}
> >  		if ((slotctl & PCI_EXP_SLTCTL_DLLSCE) && (slotctl & PCI_EXP_SLTCTL_HPIE))
> >  			mod_timer(&pcie->link_up_irq_timer, jiffies + 1);
> >  	}
> > @@ -956,6 +980,9 @@ static struct pci_bridge_emul_ops advk_pci_bridge_emul_ops = {
> >  static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
> >  {
> >  	struct pci_bridge_emul *bridge = &pcie->bridge;
> > +	struct device *dev = &pcie->pdev->dev;
> > +	u8 slot_power_limit_scale, slot_power_limit_value;
> > +	u32 slot_power_limit;
> >  	int ret;
> >  
> >  	bridge->conf.vendor =
> > @@ -988,6 +1015,40 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
> >  	/* Indicates supports for Completion Retry Status */
> >  	bridge->pcie_conf.rootcap = cpu_to_le16(PCI_EXP_RTCAP_CRSVIS);
> >  
> 
> > +	if (of_property_read_u32(dev->of_node, "slot-power-limit", &slot_power_limit))
> > +		slot_power_limit = 0;
> > +
> > +	if (slot_power_limit)
> > +		dev_info(dev, "Slot power limit %u.%uW\n", slot_power_limit / 1000,
> > +			 (slot_power_limit / 100) % 10);
> 
> Add a wrapper function for this.
> 
> > +
> > +	/* Calculate Slot Power Limit Value and Slot Power Limit Scale */
> > +	if (slot_power_limit == 0) {
> > +		slot_power_limit_scale = 0;
> > +		slot_power_limit_value = 0x00;
> > +	} else if (slot_power_limit <= 255) {
> > +		slot_power_limit_scale = 3;
> > +		slot_power_limit_value = slot_power_limit;
> > +	} else if (slot_power_limit <= 255*10) {
> > +		slot_power_limit_scale = 2;
> > +		slot_power_limit_value = slot_power_limit / 10;
> > +	} else if (slot_power_limit <= 255*100) {
> > +		slot_power_limit_scale = 1;
> > +		slot_power_limit_value = slot_power_limit / 100;
> > +	} else if (slot_power_limit <= 239*1000) {
> > +		slot_power_limit_scale = 0;
> > +		slot_power_limit_value = slot_power_limit / 1000;
> > +	} else if (slot_power_limit <= 250*1000) {
> > +		slot_power_limit_scale = 0;
> > +		slot_power_limit_value = 0xF0;
> > +	} else if (slot_power_limit <= 275*1000) {
> > +		slot_power_limit_scale = 0;
> > +		slot_power_limit_value = 0xF1;
> > +	} else {
> > +		slot_power_limit_scale = 0;
> > +		slot_power_limit_value = 0xF2;
> > +	}
> 
> This all looks like it should be common code.

Yes, this is common code. I will put it into some common function.

> > +
> >  	/*
> >  	 * Mark bridge as Hot-Plug Capable to allow delivering Data Link Layer
> >  	 * State Changed interrupt. No Command Completed Support is set because
> > @@ -996,7 +1057,10 @@ static int advk_sw_pci_bridge_init(struct advk_pcie *pcie)
> >  	 * bit permanently as there is no support for unplugging PCIe card from
> >  	 * the slot. Assume that PCIe card is always connected in slot.
> >  	 */
> > -	bridge->pcie_conf.slotcap = cpu_to_le32(PCI_EXP_SLTCAP_NCCS | PCI_EXP_SLTCAP_HPC);
> > +	bridge->pcie_conf.slotcap = cpu_to_le32(PCI_EXP_SLTCAP_NCCS |
> > +						PCI_EXP_SLTCAP_HPC |
> 
> While not new, how does the driver know the board is hotplug capable. 
> IIRC, we have a property for that.

Just ignore it for now. It is part of unfinished patches. I sent it to
show how slot_power_limit would be configured via emulated root bridge.

> > +						slot_power_limit_value << 7 |
> > +						slot_power_limit_scale << 15);
> >  	bridge->pcie_conf.slotsta = cpu_to_le16(PCI_EXP_SLTSTA_PDS);
> >  
> >  	return 0;
> > -- 
> > 2.20.1
> > 
> > 



[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux