mbox series

[v4,0/4] Simplify PCIe hotplug indicator control

Message ID 20190903111021.1559-1-efremov@linux.com (mailing list archive)
Headers show
Series Simplify PCIe hotplug indicator control | expand

Message

Denis Efremov (Oracle) Sept. 3, 2019, 11:10 a.m. UTC
PCIe defines two optional hotplug indicators: a Power indicator and an
Attention indicator. Both are controlled by the same register, and each
can be on, off or blinking. The current interfaces
(pciehp_green_led_{on,off,blink}() and pciehp_set_attention_status()) are
non-uniform and require two register writes in many cases where we could
do one.

This patchset introduces the new function pciehp_set_indicators(). It
allows one to set two indicators with a single register write. All
calls to previous interfaces (pciehp_green_led_* and
pciehp_set_attention_status()) are replaced with a new one. Thus,
the amount of duplicated code for setting indicators is reduced.

Changes in v4:
  - Changed the inputs validation in pciehp_set_indicators()
  - Moved PCI_EXP_SLTCTL_ATTN_IND_NONE, PCI_EXP_SLTCTL_PWR_IND_NONE
    to drivers/pci/hotplug/pciehp.h and set to -1 for not interfering
    with reserved values in the PCIe Base spec
  - Added set_power_indicator define

Changes in v3:
  - Changed pciehp_set_indicators() to work with existing
    PCI_EXP_SLTCTL_* macros
  - Reworked the inputs validation in pciehp_set_indicators()
  - Removed pciehp_set_attention_status() and pciehp_green_led_*()
    completely

Denis Efremov (4):
  PCI: pciehp: Add pciehp_set_indicators() to jointly set LED indicators
  PCI: pciehp: Switch LED indicators with a single write
  PCI: pciehp: Remove pciehp_set_attention_status()
  PCI: pciehp: Remove pciehp_green_led_{on,off,blink}()

 drivers/pci/hotplug/pciehp.h      | 12 ++++--
 drivers/pci/hotplug/pciehp_core.c |  7 ++-
 drivers/pci/hotplug/pciehp_ctrl.c | 26 +++++------
 drivers/pci/hotplug/pciehp_hpc.c  | 72 +++++++------------------------
 include/uapi/linux/pci_regs.h     |  1 +
 5 files changed, 45 insertions(+), 73 deletions(-)

Comments

Bjorn Helgaas Sept. 5, 2019, 9:01 p.m. UTC | #1
On Tue, Sep 03, 2019 at 02:10:17PM +0300, Denis Efremov wrote:
> PCIe defines two optional hotplug indicators: a Power indicator and an
> Attention indicator. Both are controlled by the same register, and each
> can be on, off or blinking. The current interfaces
> (pciehp_green_led_{on,off,blink}() and pciehp_set_attention_status()) are
> non-uniform and require two register writes in many cases where we could
> do one.
> 
> This patchset introduces the new function pciehp_set_indicators(). It
> allows one to set two indicators with a single register write. All
> calls to previous interfaces (pciehp_green_led_* and
> pciehp_set_attention_status()) are replaced with a new one. Thus,
> the amount of duplicated code for setting indicators is reduced.
> 
> Changes in v4:
>   - Changed the inputs validation in pciehp_set_indicators()
>   - Moved PCI_EXP_SLTCTL_ATTN_IND_NONE, PCI_EXP_SLTCTL_PWR_IND_NONE
>     to drivers/pci/hotplug/pciehp.h and set to -1 for not interfering
>     with reserved values in the PCIe Base spec
>   - Added set_power_indicator define
> 
> Changes in v3:
>   - Changed pciehp_set_indicators() to work with existing
>     PCI_EXP_SLTCTL_* macros
>   - Reworked the inputs validation in pciehp_set_indicators()
>   - Removed pciehp_set_attention_status() and pciehp_green_led_*()
>     completely
> 
> Denis Efremov (4):
>   PCI: pciehp: Add pciehp_set_indicators() to jointly set LED indicators
>   PCI: pciehp: Switch LED indicators with a single write
>   PCI: pciehp: Remove pciehp_set_attention_status()
>   PCI: pciehp: Remove pciehp_green_led_{on,off,blink}()
> 
>  drivers/pci/hotplug/pciehp.h      | 12 ++++--
>  drivers/pci/hotplug/pciehp_core.c |  7 ++-
>  drivers/pci/hotplug/pciehp_ctrl.c | 26 +++++------
>  drivers/pci/hotplug/pciehp_hpc.c  | 72 +++++++------------------------
>  include/uapi/linux/pci_regs.h     |  1 +
>  5 files changed, 45 insertions(+), 73 deletions(-)

Thanks, Denis, I applied these to pci/pciehp for v5.4.  I think this
is a great improvement.

I tweaked a few things:

  - Updated comments to refer to "Power" intead of "green",
    "Attention" instead of "amber", and "Indicator" instead of "LED".

  - Replaced PCI_EXP_SLTCTL_ATTN_IND_NONE and
    PCI_EXP_SLTCTL_PWR_IND_NONE with INDICATOR_NOOP because I didn't
    want them to look like definitions from the spec.

  - Dropped set_power_indicator().  It does make things locally easier
    to read, but I think the overall benefit of having fewer
    interfaces outweighs that.

The interdiff from your v4 is below.  Let me know if I broke anything.


diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index dcbf790b7508..654c972b8ea0 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -110,9 +110,9 @@ struct controller {
  *
  * @OFF_STATE: slot is powered off, no subordinate devices are enumerated
  * @BLINKINGON_STATE: slot will be powered on after the 5 second delay,
- *	green led is blinking
+ *	Power Indicator is blinking
  * @BLINKINGOFF_STATE: slot will be powered off after the 5 second delay,
- *	green led is blinking
+ *	Power Indicator is blinking
  * @POWERON_STATE: slot is currently powering on
  * @POWEROFF_STATE: slot is currently powering off
  * @ON_STATE: slot is powered on, subordinate devices have been enumerated
@@ -167,9 +167,7 @@ int pciehp_power_on_slot(struct controller *ctrl);
 void pciehp_power_off_slot(struct controller *ctrl);
 void pciehp_get_power_status(struct controller *ctrl, u8 *status);
 
-/* Special values for leaving indicators unchanged */
-#define PCI_EXP_SLTCTL_ATTN_IND_NONE -1 /* Attention Indicator noop */
-#define PCI_EXP_SLTCTL_PWR_IND_NONE  -1 /* Power Indicator noop */
+#define INDICATOR_NOOP -1	/* Leave indicator unchanged */
 void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);
 
 void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
@@ -187,9 +185,6 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
 int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
 int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
 
-#define set_power_indicator(ctrl, x) \
-	pciehp_set_indicators(ctrl, (x), PCI_EXP_SLTCTL_ATTN_IND_NONE)
-
 static inline const char *slot_name(struct controller *ctrl)
 {
 	return hotplug_slot_name(&ctrl->hotplug_slot);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 7a86ea90ed94..b3122c151b80 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -95,7 +95,7 @@ static void cleanup_slot(struct controller *ctrl)
 }
 
 /*
- * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ * set_attention_status - Turns the Attention Indicator on, off or blinking
  */
 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 {
@@ -108,7 +108,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
 		status = PCI_EXP_SLTCTL_ATTN_IND_OFF;
 
 	pci_config_pm_runtime_get(pdev);
-	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_NONE, status);
+	pciehp_set_indicators(ctrl, INDICATOR_NOOP, status);
 	pci_config_pm_runtime_put(pdev);
 	return 0;
 }
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index d0f55f695770..21af7b16d7a4 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -30,7 +30,10 @@
 
 static void set_slot_off(struct controller *ctrl)
 {
-	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
+	/*
+	 * Turn off slot, turn on attention indicator, turn off power
+	 * indicator
+	 */
 	if (POWER_CTRL(ctrl)) {
 		pciehp_power_off_slot(ctrl);
 
@@ -65,7 +68,8 @@ static int board_added(struct controller *ctrl)
 			return retval;
 	}
 
-	set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK);
+	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
+			      INDICATOR_NOOP);
 
 	/* Check link training status */
 	retval = pciehp_check_link_status(ctrl);
@@ -100,7 +104,7 @@ static int board_added(struct controller *ctrl)
 }
 
 /**
- * remove_board - Turns off slot and LEDs
+ * remove_board - Turn off slot and Power Indicator
  * @ctrl: PCIe hotplug controller where board is being removed
  * @safe_removal: whether the board is safely removed (versus surprise removed)
  */
@@ -123,8 +127,8 @@ static void remove_board(struct controller *ctrl, bool safe_removal)
 			   &ctrl->pending_events);
 	}
 
-	/* turn off Green LED */
-	set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF);
+	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+			      INDICATOR_NOOP);
 }
 
 static int pciehp_enable_slot(struct controller *ctrl);
@@ -171,7 +175,7 @@ void pciehp_handle_button_press(struct controller *ctrl)
 			ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
 				  slot_name(ctrl));
 		}
-		/* blink green LED and turn off amber */
+		/* blink power indicator and turn off attention */
 		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
 				      PCI_EXP_SLTCTL_ATTN_IND_OFF);
 		schedule_delayed_work(&ctrl->button_work, 5 * HZ);
@@ -312,7 +316,8 @@ static int pciehp_enable_slot(struct controller *ctrl)
 	ret = __pciehp_enable_slot(ctrl);
 	if (ret && ATTN_BUTTN(ctrl))
 		/* may be blinking */
-		set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF);
+		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+				      INDICATOR_NOOP);
 	pm_runtime_put(&ctrl->pcie->port->dev);
 
 	mutex_lock(&ctrl->state_lock);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 9fd8f99132bb..1a522c1c4177 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -418,17 +418,32 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
 	return 0;
 }
 
+/**
+ * pciehp_set_indicators() - set attention indicator, power indicator, or both
+ * @ctrl: PCIe hotplug controller
+ * @pwr: one of:
+ *	PCI_EXP_SLTCTL_PWR_IND_ON
+ *	PCI_EXP_SLTCTL_PWR_IND_BLINK
+ *	PCI_EXP_SLTCTL_PWR_IND_OFF
+ * @attn: one of:
+ *	PCI_EXP_SLTCTL_ATTN_IND_ON
+ *	PCI_EXP_SLTCTL_ATTN_IND_BLINK
+ *	PCI_EXP_SLTCTL_ATTN_IND_OFF
+ *
+ * Either @pwr or @attn can also be INDICATOR_NOOP to leave that indicator
+ * unchanged.
+ */
 void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
 {
 	u16 cmd = 0, mask = 0;
 
-	if (PWR_LED(ctrl) && pwr > 0) {
-		cmd |= pwr;
+	if (PWR_LED(ctrl) && pwr != INDICATOR_NOOP) {
+		cmd |= (pwr & PCI_EXP_SLTCTL_PIC);
 		mask |= PCI_EXP_SLTCTL_PIC;
 	}
 
-	if (ATTN_LED(ctrl) && attn > 0) {
-		cmd |= attn;
+	if (ATTN_LED(ctrl) && attn != INDICATOR_NOOP) {
+		cmd |= (attn & PCI_EXP_SLTCTL_AIC);
 		mask |= PCI_EXP_SLTCTL_AIC;
 	}
Denis Efremov (Oracle) Sept. 5, 2019, 9:16 p.m. UTC | #2
On 06.09.2019 00:01, Bjorn Helgaas wrote:
> On Tue, Sep 03, 2019 at 02:10:17PM +0300, Denis Efremov wrote:
>> PCIe defines two optional hotplug indicators: a Power indicator and an
>> Attention indicator. Both are controlled by the same register, and each
>> can be on, off or blinking. The current interfaces
>> (pciehp_green_led_{on,off,blink}() and pciehp_set_attention_status()) are
>> non-uniform and require two register writes in many cases where we could
>> do one.
>>
>> This patchset introduces the new function pciehp_set_indicators(). It
>> allows one to set two indicators with a single register write. All
>> calls to previous interfaces (pciehp_green_led_* and
>> pciehp_set_attention_status()) are replaced with a new one. Thus,
>> the amount of duplicated code for setting indicators is reduced.
>>
>> Changes in v4:
>>   - Changed the inputs validation in pciehp_set_indicators()
>>   - Moved PCI_EXP_SLTCTL_ATTN_IND_NONE, PCI_EXP_SLTCTL_PWR_IND_NONE
>>     to drivers/pci/hotplug/pciehp.h and set to -1 for not interfering
>>     with reserved values in the PCIe Base spec
>>   - Added set_power_indicator define
>>
>> Changes in v3:
>>   - Changed pciehp_set_indicators() to work with existing
>>     PCI_EXP_SLTCTL_* macros
>>   - Reworked the inputs validation in pciehp_set_indicators()
>>   - Removed pciehp_set_attention_status() and pciehp_green_led_*()
>>     completely
>>
>> Denis Efremov (4):
>>   PCI: pciehp: Add pciehp_set_indicators() to jointly set LED indicators
>>   PCI: pciehp: Switch LED indicators with a single write
>>   PCI: pciehp: Remove pciehp_set_attention_status()
>>   PCI: pciehp: Remove pciehp_green_led_{on,off,blink}()
>>
>>  drivers/pci/hotplug/pciehp.h      | 12 ++++--
>>  drivers/pci/hotplug/pciehp_core.c |  7 ++-
>>  drivers/pci/hotplug/pciehp_ctrl.c | 26 +++++------
>>  drivers/pci/hotplug/pciehp_hpc.c  | 72 +++++++------------------------
>>  include/uapi/linux/pci_regs.h     |  1 +
>>  5 files changed, 45 insertions(+), 73 deletions(-)
> 
> Thanks, Denis, I applied these to pci/pciehp for v5.4.  I think this
> is a great improvement.
> 
> I tweaked a few things:
> 
>   - Updated comments to refer to "Power" intead of "green",
>     "Attention" instead of "amber", and "Indicator" instead of "LED".
> 
>   - Replaced PCI_EXP_SLTCTL_ATTN_IND_NONE and
>     PCI_EXP_SLTCTL_PWR_IND_NONE with INDICATOR_NOOP because I didn't
>     want them to look like definitions from the spec.
> 
>   - Dropped set_power_indicator().  It does make things locally easier
>     to read, but I think the overall benefit of having fewer
>     interfaces outweighs that.
> 
> The interdiff from your v4 is below.  Let me know if I broke anything.

Thank you for the improvements. Looks good to me.

Regards,
Denis
Lukas Wunner Sept. 5, 2019, 10:03 p.m. UTC | #3
On Thu, Sep 05, 2019 at 04:01:02PM -0500, Bjorn Helgaas wrote:
>  void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
>  {
>  	u16 cmd = 0, mask = 0;
>  
> -	if (PWR_LED(ctrl) && pwr > 0) {
> -		cmd |= pwr;
> +	if (PWR_LED(ctrl) && pwr != INDICATOR_NOOP) {
> +		cmd |= (pwr & PCI_EXP_SLTCTL_PIC);
>  		mask |= PCI_EXP_SLTCTL_PIC;
>  	}
>  
> -	if (ATTN_LED(ctrl) && attn > 0) {
> -		cmd |= attn;
> +	if (ATTN_LED(ctrl) && attn != INDICATOR_NOOP) {
> +		cmd |= (attn & PCI_EXP_SLTCTL_AIC);
>  		mask |= PCI_EXP_SLTCTL_AIC;
>  	}

There's a subtle issue here:  A value of "0" is "reserved" per PCIe r4.0,
sec 7.8.10.  Denis filtered that out, with your change it's an accepted
value.  I don't think the function ever gets called with a value of "0",
so it's not a big deal.  And maybe we don't even want to filter that
value out.  Just noting anyway.

Thanks,

Lukas