2019-09-03 11:11:33

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: [PATCH v4 0/4] Simplify PCIe hotplug indicator control

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(-)

--
2.21.0


2019-09-03 11:11:40

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: [PATCH v4 1/4] PCI: pciehp: Add pciehp_set_indicators() to jointly set LED indicators

Add pciehp_set_indicators() to set power and attention indicators with a
single register write. Thus, avoiding waiting twice for Command Complete.

Signed-off-by: Denis Efremov <[email protected]>
---
drivers/pci/hotplug/pciehp.h | 5 +++++
drivers/pci/hotplug/pciehp_hpc.c | 21 +++++++++++++++++++++
2 files changed, 26 insertions(+)

diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 8c51a04b8083..0214e09e91a4 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -167,6 +167,11 @@ 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 */
+void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);
+
void pciehp_set_attention_status(struct controller *ctrl, u8 status);
void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
int pciehp_query_power_fault(struct controller *ctrl);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index bd990e3371e3..4d0fe39ef049 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -443,6 +443,27 @@ void pciehp_set_attention_status(struct controller *ctrl, u8 value)
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
}

+void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
+{
+ u16 cmd = 0, mask = 0;
+
+ if (PWR_LED(ctrl) && pwr > 0) {
+ cmd |= pwr;
+ mask |= PCI_EXP_SLTCTL_PIC;
+ }
+
+ if (ATTN_LED(ctrl) && attn > 0) {
+ cmd |= attn;
+ mask |= PCI_EXP_SLTCTL_AIC;
+ }
+
+ if (cmd) {
+ pcie_write_cmd_nowait(ctrl, cmd, mask);
+ ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
+ pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
+ }
+}
+
void pciehp_green_led_on(struct controller *ctrl)
{
if (!PWR_LED(ctrl))
--
2.21.0

2019-09-03 11:12:02

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: [PATCH v4 2/4] PCI: pciehp: Switch LED indicators with a single write

This patch replaces all consecutive switches of power and attention
indicators with pciehp_set_indicators() call. Thus, performing only
single write to a register.

Reviewed-by: Kuppuswamy Sathyanarayanan <[email protected]>
Reviewed-by: Lukas Wunner <[email protected]>
Signed-off-by: Denis Efremov <[email protected]>
---
drivers/pci/hotplug/pciehp_ctrl.c | 19 ++++++++++---------
drivers/pci/hotplug/pciehp_hpc.c | 4 ++--
2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 631ced0ab28a..232f7bfcfce9 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -42,8 +42,8 @@ static void set_slot_off(struct controller *ctrl)
msleep(1000);
}

- pciehp_green_led_off(ctrl);
- pciehp_set_attention_status(ctrl, 1);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+ PCI_EXP_SLTCTL_ATTN_IND_ON);
}

/**
@@ -90,8 +90,8 @@ static int board_added(struct controller *ctrl)
}
}

- pciehp_green_led_on(ctrl);
- pciehp_set_attention_status(ctrl, 0);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
+ PCI_EXP_SLTCTL_ATTN_IND_OFF);
return 0;

err_exit:
@@ -172,8 +172,8 @@ void pciehp_handle_button_press(struct controller *ctrl)
slot_name(ctrl));
}
/* blink green LED and turn off amber */
- pciehp_green_led_blink(ctrl);
- pciehp_set_attention_status(ctrl, 0);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
+ PCI_EXP_SLTCTL_ATTN_IND_OFF);
schedule_delayed_work(&ctrl->button_work, 5 * HZ);
break;
case BLINKINGOFF_STATE:
@@ -187,12 +187,13 @@ void pciehp_handle_button_press(struct controller *ctrl)
cancel_delayed_work(&ctrl->button_work);
if (ctrl->state == BLINKINGOFF_STATE) {
ctrl->state = ON_STATE;
- pciehp_green_led_on(ctrl);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
+ PCI_EXP_SLTCTL_ATTN_IND_OFF);
} else {
ctrl->state = OFF_STATE;
- pciehp_green_led_off(ctrl);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+ PCI_EXP_SLTCTL_ATTN_IND_OFF);
}
- pciehp_set_attention_status(ctrl, 0);
ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
slot_name(ctrl));
break;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 4d0fe39ef049..d2c60d844d30 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -659,8 +659,8 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
if ((events & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
ctrl->power_fault_detected = 1;
ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
- pciehp_set_attention_status(ctrl, 1);
- pciehp_green_led_off(ctrl);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
+ PCI_EXP_SLTCTL_ATTN_IND_ON);
}

/*
--
2.21.0

2019-09-03 11:12:06

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: [PATCH v4 3/4] PCI: pciehp: Remove pciehp_set_attention_status()

Remove pciehp_set_attention_status() and use pciehp_set_indicators()
instead, since the code is mostly the same.

Reviewed-by: Kuppuswamy Sathyanarayanan <[email protected]>
Signed-off-by: Denis Efremov <[email protected]>
---
drivers/pci/hotplug/pciehp.h | 1 -
drivers/pci/hotplug/pciehp_core.c | 7 ++++++-
drivers/pci/hotplug/pciehp_hpc.c | 25 -------------------------
include/uapi/linux/pci_regs.h | 1 +
4 files changed, 7 insertions(+), 27 deletions(-)

diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 0214e09e91a4..cf59f70a33cc 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -172,7 +172,6 @@ void pciehp_get_power_status(struct controller *ctrl, u8 *status);
#define PCI_EXP_SLTCTL_PWR_IND_NONE -1 /* Power Indicator noop */
void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);

-void pciehp_set_attention_status(struct controller *ctrl, u8 status);
void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
int pciehp_query_power_fault(struct controller *ctrl);
void pciehp_green_led_on(struct controller *ctrl);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 6ad0d86762cb..7a86ea90ed94 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -102,8 +102,13 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
struct controller *ctrl = to_ctrl(hotplug_slot);
struct pci_dev *pdev = ctrl->pcie->port;

+ if (status)
+ status <<= PCI_EXP_SLTCTL_ATTN_IND_SHIFT;
+ else
+ status = PCI_EXP_SLTCTL_ATTN_IND_OFF;
+
pci_config_pm_runtime_get(pdev);
- pciehp_set_attention_status(ctrl, status);
+ pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_NONE, status);
pci_config_pm_runtime_put(pdev);
return 0;
}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index d2c60d844d30..eeac2e704c75 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -418,31 +418,6 @@ int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
return 0;
}

-void pciehp_set_attention_status(struct controller *ctrl, u8 value)
-{
- u16 slot_cmd;
-
- if (!ATTN_LED(ctrl))
- return;
-
- switch (value) {
- case 0: /* turn off */
- slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_OFF;
- break;
- case 1: /* turn on */
- slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_ON;
- break;
- case 2: /* turn blink */
- slot_cmd = PCI_EXP_SLTCTL_ATTN_IND_BLINK;
- break;
- default:
- return;
- }
- pcie_write_cmd_nowait(ctrl, slot_cmd, PCI_EXP_SLTCTL_AIC);
- ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
- pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
-}
-
void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
{
u16 cmd = 0, mask = 0;
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index f28e562d7ca8..de3e58afc564 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -591,6 +591,7 @@
#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */
#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */
#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */
+#define PCI_EXP_SLTCTL_ATTN_IND_SHIFT 6 /* Attention Indicator shift */
#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040 /* Attention Indicator on */
#define PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080 /* Attention Indicator blinking */
#define PCI_EXP_SLTCTL_ATTN_IND_OFF 0x00c0 /* Attention Indicator off */
--
2.21.0

2019-09-03 11:14:09

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: [PATCH v4 4/4] PCI: pciehp: Remove pciehp_green_led_{on,off,blink}()

Remove pciehp_green_led_{on,off,blink}() and use pciehp_set_indicators()
instead, since the code is mostly the same.

Reviewed-by: Kuppuswamy Sathyanarayanan <[email protected]>
Signed-off-by: Denis Efremov <[email protected]>
---
drivers/pci/hotplug/pciehp.h | 6 +++---
drivers/pci/hotplug/pciehp_ctrl.c | 7 +++---
drivers/pci/hotplug/pciehp_hpc.c | 36 -------------------------------
3 files changed, 7 insertions(+), 42 deletions(-)

diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index cf59f70a33cc..dcbf790b7508 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -174,9 +174,6 @@ void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn);

void pciehp_get_latch_status(struct controller *ctrl, u8 *status);
int pciehp_query_power_fault(struct controller *ctrl);
-void pciehp_green_led_on(struct controller *ctrl);
-void pciehp_green_led_off(struct controller *ctrl);
-void pciehp_green_led_blink(struct controller *ctrl);
bool pciehp_card_present(struct controller *ctrl);
bool pciehp_card_present_or_link_active(struct controller *ctrl);
int pciehp_check_link_status(struct controller *ctrl);
@@ -190,6 +187,9 @@ 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_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 232f7bfcfce9..d0f55f695770 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -65,7 +65,7 @@ static int board_added(struct controller *ctrl)
return retval;
}

- pciehp_green_led_blink(ctrl);
+ set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK);

/* Check link training status */
retval = pciehp_check_link_status(ctrl);
@@ -124,7 +124,7 @@ static void remove_board(struct controller *ctrl, bool safe_removal)
}

/* turn off Green LED */
- pciehp_green_led_off(ctrl);
+ set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF);
}

static int pciehp_enable_slot(struct controller *ctrl);
@@ -311,7 +311,8 @@ static int pciehp_enable_slot(struct controller *ctrl)
pm_runtime_get_sync(&ctrl->pcie->port->dev);
ret = __pciehp_enable_slot(ctrl);
if (ret && ATTN_BUTTN(ctrl))
- pciehp_green_led_off(ctrl); /* may be blinking */
+ /* may be blinking */
+ set_power_indicator(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF);
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 eeac2e704c75..9fd8f99132bb 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -439,42 +439,6 @@ void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
}
}

-void pciehp_green_led_on(struct controller *ctrl)
-{
- if (!PWR_LED(ctrl))
- return;
-
- pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
- PCI_EXP_SLTCTL_PIC);
- ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
- pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PWR_IND_ON);
-}
-
-void pciehp_green_led_off(struct controller *ctrl)
-{
- if (!PWR_LED(ctrl))
- return;
-
- pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
- PCI_EXP_SLTCTL_PIC);
- ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
- pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PWR_IND_OFF);
-}
-
-void pciehp_green_led_blink(struct controller *ctrl)
-{
- if (!PWR_LED(ctrl))
- return;
-
- pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
- PCI_EXP_SLTCTL_PIC);
- ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
- pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
- PCI_EXP_SLTCTL_PWR_IND_BLINK);
-}
-
int pciehp_power_on_slot(struct controller *ctrl)
{
struct pci_dev *pdev = ctrl_dev(ctrl);
--
2.21.0

2019-09-06 07:17:45

by Denis Efremov (Oracle)

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Simplify PCIe hotplug indicator control



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

2019-09-06 08:51:23

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Simplify PCIe hotplug indicator control

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;
}

2019-09-06 09:07:09

by Lukas Wunner

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Simplify PCIe hotplug indicator control

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