diff mbox series

[v1] PCI: pciehp: Make sure DPC trigger status is reset in PDC handler

Message ID 20230615062559.1268404-1-sathyanarayanan.kuppuswamy@linux.intel.com (mailing list archive)
State Changes Requested
Delegated to: Bjorn Helgaas
Headers show
Series [v1] PCI: pciehp: Make sure DPC trigger status is reset in PDC handler | expand

Commit Message

Kuppuswamy Sathyanarayanan June 15, 2023, 6:25 a.m. UTC
During the EDR-based DPC recovery process, for devices with persistent
issues, the firmware may choose not to handle the DPC error and leave
the port in DPC triggered state. In such scenarios, if the user
replaces the faulty device with a new one, the OS is expected to clear
the DPC trigger status in the hotplug error handler to enable the new
device enumeration. More details about this issue can be found in PCIe
firmware specification, r3.3, sec titled "DPC Event Handling"
Implementation note.

Similar issue might also happen if the DPC or EDR recovery handler
exits before clearing the trigger status. To fix this issue, clear the
DPC trigger status in PDC interrupt handler.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reported-by: Thatchanamurthy Satish <Satish.Thatchanamurt@Dell.com>
---
 drivers/pci/hotplug/pciehp_hpc.c |  6 +++++
 drivers/pci/pci.h                |  4 ++++
 drivers/pci/pcie/dpc.c           | 40 ++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)

Comments

kernel test robot June 15, 2023, 8:18 a.m. UTC | #1
Hi Kuppuswamy,

kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on pci/for-linus linus/master v6.4-rc6 next-20230615]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Kuppuswamy-Sathyanarayanan/PCI-pciehp-Make-sure-DPC-trigger-status-is-reset-in-PDC-handler/20230615-142706
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20230615062559.1268404-1-sathyanarayanan.kuppuswamy%40linux.intel.com
patch subject: [PATCH v1] PCI: pciehp: Make sure DPC trigger status is reset in PDC handler
config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20230615/202306151528.9ZEmHZMt-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        git remote add pci https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git
        git fetch pci next
        git checkout pci/next
        b4 shazam https://lore.kernel.org/r/20230615062559.1268404-1-sathyanarayanan.kuppuswamy@linux.intel.com
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=alpha olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=alpha SHELL=/bin/bash drivers/pci/

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306151528.9ZEmHZMt-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/pci/pcie/dpc.c:123: warning: expecting prototype for pci_reset_trigger(). Prototype was for pci_dpc_reset_trigger() instead


vim +123 drivers/pci/pcie/dpc.c

   114	
   115	/**
   116	 * pci_reset_trigger - Clear DPC trigger status
   117	 * @pdev: PCI device
   118	 *
   119	 * It is called from the PCIe hotplug driver to clean the DPC
   120	 * trigger status in the PDC interrupt handler.
   121	 */
   122	void pci_dpc_reset_trigger(struct pci_dev *pdev)
 > 123	{
   124		if (!pdev->dpc_cap)
   125			return;
   126	
   127		pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
   128				      PCI_EXP_DPC_STATUS_TRIGGER);
   129	}
   130
Lukas Wunner June 15, 2023, 6:35 p.m. UTC | #2
On Wed, Jun 14, 2023 at 11:25:59PM -0700, Kuppuswamy Sathyanarayanan wrote:
> During the EDR-based DPC recovery process, for devices with persistent
> issues, the firmware may choose not to handle the DPC error and leave
> the port in DPC triggered state. In such scenarios, if the user
> replaces the faulty device with a new one, the OS is expected to clear
> the DPC trigger status in the hotplug error handler to enable the new
> device enumeration.

You're clearing the DPC trigger status upon a PDC event, yet are saying
here the purpose is to reset port state for a future hotplugged device.

A PDC event may be synthesized, e.g. to trigger slot bringup via
sysfs, so using a PDC event to clear DPC trigger status feels wrong.
pciehp_unconfigure_device() seems like a more appropriate place to me.


> More details about this issue can be found in PCIe
> firmware specification, r3.3, sec titled "DPC Event Handling"
> Implementation note.

That Implementation Note contains a lot of text and a fairly complex
flow chart. If you could point to specific paragraphs or numbers in
the Implementation Note that would make life easier for a reviewer
to make the connection between your code and the spec.


> Similar issue might also happen if the DPC or EDR recovery handler
> exits before clearing the trigger status. To fix this issue, clear the
> DPC trigger status in PDC interrupt handler.

I was about to ask why the code is added to dpc.c, not edr.c,
and why it's not constrained to CONFIG_PCIE_EDR, but I assume
that's the reason?  Because it "might" happen for OS-native DPC
as well?


> +/**
> + * pci_reset_trigger - Clear DPC trigger status
> + * @pdev: PCI device
> + *
> + * It is called from the PCIe hotplug driver to clean the DPC
> + * trigger status in the PDC interrupt handler.
> + */
> +void pci_dpc_reset_trigger(struct pci_dev *pdev)
> +{
> +	if (!pdev->dpc_cap)
> +		return;
> +
> +	pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
> +			      PCI_EXP_DPC_STATUS_TRIGGER);
> +}

This may run concurrently to dpc_reset_link(), so I'd expect that
you need some kind of serialization.  What happens if pciehp clears
trigger status behind the DPC driver's back while it is handling an
error?

Thanks,

Lukas
Kuppuswamy Sathyanarayanan June 15, 2023, 11:03 p.m. UTC | #3
Hi Lukas,

Thanks for the review.

On 6/15/23 11:35 AM, Lukas Wunner wrote:
> On Wed, Jun 14, 2023 at 11:25:59PM -0700, Kuppuswamy Sathyanarayanan wrote:
>> During the EDR-based DPC recovery process, for devices with persistent
>> issues, the firmware may choose not to handle the DPC error and leave
>> the port in DPC triggered state. In such scenarios, if the user
>> replaces the faulty device with a new one, the OS is expected to clear
>> the DPC trigger status in the hotplug error handler to enable the new
>> device enumeration.
> 
> You're clearing the DPC trigger status upon a PDC event, yet are saying
> here the purpose is to reset port state for a future hotplugged device.

Sorry, it is a typo. I meant "hotplug interrupt handler".

The goal is to ensure that when a new device presence is detected, the
old DPC trigger status is cleared.

> 
> A PDC event may be synthesized, e.g. to trigger slot bringup via
> sysfs, so using a PDC event to clear DPC trigger status feels wrong.

IMO, it is harmless. We just want to make sure the previous DPC trigger
status is cleared before enumerating a new device.

> pciehp_unconfigure_device() seems like a more appropriate place to me.
> 

I initially thought to add it there. Spec also recommends clearing it
when removing the device. But I wasn't sure if pciehp_unconfigure_device()
would be called only during device removal. 

Let me test this path and get back to you.

> 
>> More details about this issue can be found in PCIe
>> firmware specification, r3.3, sec titled "DPC Event Handling"
>> Implementation note.
> 
> That Implementation Note contains a lot of text and a fairly complex
> flow chart. If you could point to specific paragraphs or numbers in
> the Implementation Note that would make life easier for a reviewer
> to make the connection between your code and the spec.

It is the text at the end of the flowchart. Copied it here for reference.

For devices with persistent errors, a port may be kept in the DPC triggered
state (disabled) to keep those devices from continuing to generate errors. For
hot-plug slots, the errant device may be removed and replaced with a new device.
If the DPC trigger state is not cleared, then the port above the newly inserted
device will still be disabled and will be non-operational. Therefore, operating
systems may need to modify their hot-plug interrupt handling code to clear DPC
Trigger Status when a device is removed so that a subsequent insertion
will succeed.

> 
> 
>> Similar issue might also happen if the DPC or EDR recovery handler
>> exits before clearing the trigger status. To fix this issue, clear the
>> DPC trigger status in PDC interrupt handler.
> 
> I was about to ask why the code is added to dpc.c, not edr.c,
> and why it's not constrained to CONFIG_PCIE_EDR, but I assume
> that's the reason?  Because it "might" happen for OS-native DPC
> as well?

Yes. There are code paths in the DPC driver where error recover handler
can exit before clearing the DPC trigger status. So I think this fix is
applicable for native code as well.

> 
> 
>> +/**
>> + * pci_reset_trigger - Clear DPC trigger status
>> + * @pdev: PCI device
>> + *
>> + * It is called from the PCIe hotplug driver to clean the DPC
>> + * trigger status in the PDC interrupt handler.
>> + */
>> +void pci_dpc_reset_trigger(struct pci_dev *pdev)
>> +{
>> +	if (!pdev->dpc_cap)
>> +		return;
>> +
>> +	pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
>> +			      PCI_EXP_DPC_STATUS_TRIGGER);
>> +}
> 
> This may run concurrently to dpc_reset_link(), so I'd expect that
> you need some kind of serialization.  What happens if pciehp clears
> trigger status behind the DPC driver's back while it is handling an
> error?

Currently, we only call pci_dpc_reset_trigger() in PDC interrupt handler.

Do you think there would be a race between error handler and PDC handler?

> 
> Thanks,
> 
> Lukas
Lukas Wunner June 16, 2023, 9:06 a.m. UTC | #4
[cc += Smita]

On Thu, Jun 15, 2023 at 04:03:54PM -0700, Sathyanarayanan Kuppuswamy wrote:
> On 6/15/23 11:35 AM, Lukas Wunner wrote:
> > On Wed, Jun 14, 2023 at 11:25:59PM -0700, Kuppuswamy Sathyanarayanan wrote:
> > > During the EDR-based DPC recovery process, for devices with persistent
> > > issues, the firmware may choose not to handle the DPC error and leave
> > > the port in DPC triggered state. In such scenarios, if the user
> > > replaces the faulty device with a new one, the OS is expected to clear
> > > the DPC trigger status in the hotplug error handler to enable the new
> > > device enumeration.
[...]
> > 
> > pciehp_unconfigure_device() seems like a more appropriate place to me.
> > 
> 
> I initially thought to add it there. Spec also recommends clearing it
> when removing the device. But I wasn't sure if pciehp_unconfigure_device()
> would be called only during device removal.

It is.


> > > More details about this issue can be found in PCIe
> > > firmware specification, r3.3, sec titled "DPC Event Handling"
> > > Implementation note.
> > 
> > That Implementation Note contains a lot of text and a fairly complex
> > flow chart. If you could point to specific paragraphs or numbers in
> > the Implementation Note that would make life easier for a reviewer
> > to make the connection between your code and the spec.
> 
> It is the text at the end of the flowchart. Copied it here for reference.
> 
> For devices with persistent errors, a port may be kept in the DPC triggered
> state (disabled) to keep those devices from continuing to generate errors.
> For hot-plug slots, the errant device may be removed and replaced with a new
> device.
> If the DPC trigger state is not cleared, then the port above the newly
> inserted device will still be disabled and will be non-operational.
> Therefore, operating systems may need to modify their hot-plug interrupt
> handling code to clear DPC Trigger Status when a device is removed so that
> a subsequent insertion will succeed.

Please add that excerpt to the commit message.


> > This may run concurrently to dpc_reset_link(), so I'd expect that
> > you need some kind of serialization.  What happens if pciehp clears
> > trigger status behind the DPC driver's back while it is handling an
> > error?
> 
> Currently, we only call pci_dpc_reset_trigger() in PDC interrupt handler.
> 
> Do you think there would be a race between error handler and PDC handler?

Yes I think so.

We need to differentiate between two cases:

(1) DPC handled by firmware, hotplug handled by OS:

    In this case clearing DPC trigger status from pciehp device removal
    code path seems reasonable.  But it must be constrained to
    !host_bridge->native_dpc.

(2) DPC handled by OS:

    In this case clearing DPC trigger status from pciehp could race with
    the dpc interrupt handler so must not be done.  Instead, I recommend
    clearing trigger status from the dpc interrupt handler.  You should
    see a Surprise Down error handled by the dpc interrupt handler.
    Make sure DPC trigger status is *always* cleared in that case.
    
    Note that Smita Koralahalli is currently working on something similar:
    
    https://lore.kernel.org/linux-pci/20230418210526.36514-2-Smita.KoralahalliChannabasappa@amd.com/

    (@Smita sorry for the delay, I'll get to your patches ASAP.)

I recommend splitting the two cases above into two commits, one for
firmware-handled DPC and one for OS-native DPC.  IIUC, you only need
the former to address Dell's finding.

Thanks,

Lukas
Kuppuswamy Sathyanarayanan June 16, 2023, 11:27 p.m. UTC | #5
Hi Lukas,

On 6/16/23 2:06 AM, Lukas Wunner wrote:
> [cc += Smita]
> 
> On Thu, Jun 15, 2023 at 04:03:54PM -0700, Sathyanarayanan Kuppuswamy wrote:
>> On 6/15/23 11:35 AM, Lukas Wunner wrote:
>>> On Wed, Jun 14, 2023 at 11:25:59PM -0700, Kuppuswamy Sathyanarayanan wrote:
>>>> During the EDR-based DPC recovery process, for devices with persistent
>>>> issues, the firmware may choose not to handle the DPC error and leave
>>>> the port in DPC triggered state. In such scenarios, if the user
>>>> replaces the faulty device with a new one, the OS is expected to clear
>>>> the DPC trigger status in the hotplug error handler to enable the new
>>>> device enumeration.
> [...]
>>>
>>> pciehp_unconfigure_device() seems like a more appropriate place to me.
>>>
>>
>> I initially thought to add it there. Spec also recommends clearing it
>> when removing the device. But I wasn't sure if pciehp_unconfigure_device()
>> would be called only during device removal.
> 
> It is.

Do you know how pciehp_unconfigure_device() will be called when the device is
removed? Is it due to a DLLSC event or a PDC state change? If it is DLLSC,
pciehp_unconfigure_device() may not be called because we ignore the DLLSC event
if there is an active DPC trigger.


> 
> 
>>>> More details about this issue can be found in PCIe
>>>> firmware specification, r3.3, sec titled "DPC Event Handling"
>>>> Implementation note.
>>>
>>> That Implementation Note contains a lot of text and a fairly complex
>>> flow chart. If you could point to specific paragraphs or numbers in
>>> the Implementation Note that would make life easier for a reviewer
>>> to make the connection between your code and the spec.
>>
>> It is the text at the end of the flowchart. Copied it here for reference.
>>
>> For devices with persistent errors, a port may be kept in the DPC triggered
>> state (disabled) to keep those devices from continuing to generate errors.
>> For hot-plug slots, the errant device may be removed and replaced with a new
>> device.
>> If the DPC trigger state is not cleared, then the port above the newly
>> inserted device will still be disabled and will be non-operational.
>> Therefore, operating systems may need to modify their hot-plug interrupt
>> handling code to clear DPC Trigger Status when a device is removed so that
>> a subsequent insertion will succeed.
> 
> Please add that excerpt to the commit message.

Ok. I will add it.

> 
> 
>>> This may run concurrently to dpc_reset_link(), so I'd expect that
>>> you need some kind of serialization.  What happens if pciehp clears
>>> trigger status behind the DPC driver's back while it is handling an
>>> error?
>>
>> Currently, we only call pci_dpc_reset_trigger() in PDC interrupt handler.
>>
>> Do you think there would be a race between error handler and PDC handler?
> 
> Yes I think so.
> 
> We need to differentiate between two cases:
> 
> (1) DPC handled by firmware, hotplug handled by OS:
> 
>     In this case clearing DPC trigger status from pciehp device removal
>     code path seems reasonable.  But it must be constrained to
>     !host_bridge->native_dpc.

Agree.

> 
> (2) DPC handled by OS:
> 
>     In this case clearing DPC trigger status from pciehp could race with
>     the dpc interrupt handler so must not be done.  Instead, I recommend

If we clear the DPC trigger status in the DLLSC state change handler, I
agree there could be a race. However, if we clear the DPC trigger in the
PDC state change handler, I believe it will not race because the device
has already been removed. Is my understanding correct?

>     clearing trigger status from the dpc interrupt handler.  You should
>     see a Surprise Down error handled by the dpc interrupt handler.
>     Make sure DPC trigger status is *always* cleared in that case.
>     
>     Note that Smita Koralahalli is currently working on something similar:
>     
>     https://lore.kernel.org/linux-pci/20230418210526.36514-2-Smita.KoralahalliChannabasappa@amd.com/
> 
>     (@Smita sorry for the delay, I'll get to your patches ASAP.)
> 
> I recommend splitting the two cases above into two commits, one for
> firmware-handled DPC and one for OS-native DPC.  IIUC, you only need
> the former to address Dell's finding.
> 
> Thanks,
> 
> Lukas
Lukas Wunner June 17, 2023, 8:31 a.m. UTC | #6
On Fri, Jun 16, 2023 at 04:27:33PM -0700, Sathyanarayanan Kuppuswamy wrote:
> On 6/16/23 2:06 AM, Lukas Wunner wrote:
> > On Thu, Jun 15, 2023 at 04:03:54PM -0700, Sathyanarayanan Kuppuswamy wrote:
> >> On 6/15/23 11:35 AM, Lukas Wunner wrote:
> >>> On Wed, Jun 14, 2023 at 11:25:59PM -0700, Kuppuswamy Sathyanarayanan wrote:
> >>>> During the EDR-based DPC recovery process, for devices with persistent
> >>>> issues, the firmware may choose not to handle the DPC error and leave
> >>>> the port in DPC triggered state. In such scenarios, if the user
> >>>> replaces the faulty device with a new one, the OS is expected to clear
> >>>> the DPC trigger status in the hotplug error handler to enable the new
> >>>> device enumeration.
> > [...]
> >>> pciehp_unconfigure_device() seems like a more appropriate place to me.
> >>
> >> I initially thought to add it there. Spec also recommends clearing it
> >> when removing the device. But I wasn't sure if pciehp_unconfigure_device()
> >> would be called only during device removal.
> > 
> > It is.
> 
> Do you know how pciehp_unconfigure_device() will be called when the device is
> removed? Is it due to a DLLSC event or a PDC state change? If it is DLLSC,
> pciehp_unconfigure_device() may not be called because we ignore the DLLSC
> event if there is an active DPC trigger.

A DLLSC event is only ignored by pciehp if successful recovery
from DPC was possible.  In that case, the device in the slot is
still the *same*.

And you're saying in the commit message that you seek to fix the
case when "the user replaces the faulty device with a *new* one".

So for your goal, ignored DLLSC events shouldn't be relevant.

As to your question, pciehp_ist() doesn't really differentiate
between PDC and DLLSC events.  If either of them occurs,
the slot is brought down through pciehp_handle_presence_or_link_change().

And that will end up in pciehp_unconfigure_device().

I think right at the end of that function, after
pci_unlock_rescan_remove() would be a good place to perform
cleanup of the hotplug port before a newly hotplugged device
can be handled.

Smita's clearing of ARI Forwarding Enable, AtomicOp Requester Enable
and 10-Bit Tag Requester Enable could be done as well at the end of
pciehp_unconfigure_device().


> > We need to differentiate between two cases:
> > 
> > (1) DPC handled by firmware, hotplug handled by OS:
> > 
> >     In this case clearing DPC trigger status from pciehp device removal
> >     code path seems reasonable.  But it must be constrained to
> >     !host_bridge->native_dpc.
> 
> Agree.

The crucial thing here is that the dpc driver isn't bound to the
port if DPC is handled by firmware.  Hence there's no chance of
racing with dpc_reset_link() and it's safe to clear DPC trigger
status from pciehp.


> > (2) DPC handled by OS:
> > 
> >     In this case clearing DPC trigger status from pciehp could race with
> >     the dpc interrupt handler so must not be done.  Instead, I recommend
> 
> If we clear the DPC trigger status in the DLLSC state change handler, I
> agree there could be a race. However, if we clear the DPC trigger in the
> PDC state change handler, I believe it will not race because the device
> has already been removed. Is my understanding correct?

Unfortunately it's not guaranteed that dpc_reset_link() is finished
when pciehp brings down the slot.

So clearing DPC trigger status can only be done safely from the dpc
driver itself (if DPC is handled natively by the OS).

Thanks,

Lukas
diff mbox series

Patch

diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index f8c70115b691..03f8f18a6cf5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -735,6 +735,12 @@  static irqreturn_t pciehp_ist(int irq, void *dev_id)
 				      PCI_EXP_SLTCTL_ATTN_IND_ON);
 	}
 
+	/* Clear DPC trigger status */
+	if ((events & PCI_EXP_SLTSTA_PDC) && pci_dpc_is_triggered(pdev)) {
+		ctrl_dbg(ctrl, "Slot(%s): Clear DPC trigger\n", slot_name(ctrl));
+		pci_dpc_reset_trigger(pdev);
+	}
+
 	/*
 	 * Ignore Link Down/Up events caused by Downstream Port Containment
 	 * if recovery from the error succeeded.
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 2475098f6518..bbe70e9ab747 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -426,11 +426,15 @@  void pci_dpc_init(struct pci_dev *pdev);
 void dpc_process_error(struct pci_dev *pdev);
 pci_ers_result_t dpc_reset_link(struct pci_dev *pdev);
 bool pci_dpc_recovered(struct pci_dev *pdev);
+bool pci_dpc_is_triggered(struct pci_dev *pdev);
+void pci_dpc_reset_trigger(struct pci_dev *pdev);
 #else
 static inline void pci_save_dpc_state(struct pci_dev *dev) {}
 static inline void pci_restore_dpc_state(struct pci_dev *dev) {}
 static inline void pci_dpc_init(struct pci_dev *pdev) {}
 static inline bool pci_dpc_recovered(struct pci_dev *pdev) { return false; }
+static inline bool pci_dpc_is_triggered(struct pci_dev *pdev) { return false; }
+static inline void pci_dpc_reset_trigger(struct pci_dev *pdev) {}
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index 3ceed8e3de41..ccdc90d37f6d 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -88,6 +88,46 @@  static bool dpc_completed(struct pci_dev *pdev)
 	return true;
 }
 
+/**
+ * pci_dpc_is_triggered - Check for DPC trigger status
+ * @pdev: PCI device
+ *
+ * It is called from the PCIe hotplug driver to check for DPC
+ * trigger status.
+ *
+ * Return True if DPC is triggered or false for other cases.
+ */
+bool pci_dpc_is_triggered(struct pci_dev *pdev)
+{
+	u16 status;
+
+	if (!pdev->dpc_cap)
+		return false;
+
+	pci_read_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, &status);
+
+	if ((!PCI_POSSIBLE_ERROR(status)) && (status & PCI_EXP_DPC_STATUS_TRIGGER))
+		return true;
+
+	return false;
+}
+
+/**
+ * pci_reset_trigger - Clear DPC trigger status
+ * @pdev: PCI device
+ *
+ * It is called from the PCIe hotplug driver to clean the DPC
+ * trigger status in the PDC interrupt handler.
+ */
+void pci_dpc_reset_trigger(struct pci_dev *pdev)
+{
+	if (!pdev->dpc_cap)
+		return;
+
+	pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS,
+			      PCI_EXP_DPC_STATUS_TRIGGER);
+}
+
 /**
  * pci_dpc_recovered - whether DPC triggered and has recovered successfully
  * @pdev: PCI device