@@ -563,29 +563,59 @@ void pciehp_power_off_slot(struct controller *ctrl)
563563 PCI_EXP_SLTCTL_PWR_OFF );
564564}
565565
566- static void pciehp_ignore_dpc_link_change (struct controller * ctrl ,
567- struct pci_dev * pdev , int irq )
566+ bool pciehp_device_replaced (struct controller * ctrl )
567+ {
568+ struct pci_dev * pdev __free (pci_dev_put ) = NULL ;
569+ u32 reg ;
570+
571+ if (pci_dev_is_disconnected (ctrl -> pcie -> port ))
572+ return false;
573+
574+ pdev = pci_get_slot (ctrl -> pcie -> port -> subordinate , PCI_DEVFN (0 , 0 ));
575+ if (!pdev )
576+ return true;
577+
578+ if (pci_read_config_dword (pdev , PCI_VENDOR_ID , & reg ) ||
579+ reg != (pdev -> vendor | (pdev -> device << 16 )) ||
580+ pci_read_config_dword (pdev , PCI_CLASS_REVISION , & reg ) ||
581+ reg != (pdev -> revision | (pdev -> class << 8 )))
582+ return true;
583+
584+ if (pdev -> hdr_type == PCI_HEADER_TYPE_NORMAL &&
585+ (pci_read_config_dword (pdev , PCI_SUBSYSTEM_VENDOR_ID , & reg ) ||
586+ reg != (pdev -> subsystem_vendor | (pdev -> subsystem_device << 16 ))))
587+ return true;
588+
589+ if (pci_get_dsn (pdev ) != ctrl -> dsn )
590+ return true;
591+
592+ return false;
593+ }
594+
595+ static void pciehp_ignore_link_change (struct controller * ctrl ,
596+ struct pci_dev * pdev , int irq ,
597+ u16 ignored_events )
568598{
569599 /*
570600 * Ignore link changes which occurred while waiting for DPC recovery.
571601 * Could be several if DPC triggered multiple times consecutively.
602+ * Also ignore link changes caused by Secondary Bus Reset, etc.
572603 */
573604 synchronize_hardirq (irq );
574- atomic_and (~PCI_EXP_SLTSTA_DLLSC , & ctrl -> pending_events );
605+ atomic_and (~ignored_events , & ctrl -> pending_events );
575606 if (pciehp_poll_mode )
576607 pcie_capability_write_word (pdev , PCI_EXP_SLTSTA ,
577- PCI_EXP_SLTSTA_DLLSC );
578- ctrl_info (ctrl , "Slot(%s): Link Down/Up ignored (recovered by DPC)\n" ,
579- slot_name (ctrl ));
608+ ignored_events );
609+ ctrl_info (ctrl , "Slot(%s): Link Down/Up ignored\n" , slot_name (ctrl ));
580610
581611 /*
582612 * If the link is unexpectedly down after successful recovery,
583613 * the corresponding link change may have been ignored above.
584614 * Synthesize it to ensure that it is acted on.
585615 */
586616 down_read_nested (& ctrl -> reset_lock , ctrl -> depth );
587- if (!pciehp_check_link_active (ctrl ))
588- pciehp_request (ctrl , PCI_EXP_SLTSTA_DLLSC );
617+ if (!pciehp_check_link_active (ctrl ) || pciehp_device_replaced ( ctrl ) )
618+ pciehp_request (ctrl , ignored_events );
589619 up_read (& ctrl -> reset_lock );
590620}
591621
@@ -732,12 +762,19 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
732762
733763 /*
734764 * Ignore Link Down/Up events caused by Downstream Port Containment
735- * if recovery from the error succeeded.
765+ * if recovery succeeded, or caused by Secondary Bus Reset,
766+ * suspend to D3cold, firmware update, FPGA reconfiguration, etc.
736767 */
737- if ((events & PCI_EXP_SLTSTA_DLLSC ) && pci_dpc_recovered (pdev ) &&
768+ if ((events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC )) &&
769+ (pci_dpc_recovered (pdev ) || pci_hp_spurious_link_change (pdev )) &&
738770 ctrl -> state == ON_STATE ) {
739- events &= ~PCI_EXP_SLTSTA_DLLSC ;
740- pciehp_ignore_dpc_link_change (ctrl , pdev , irq );
771+ u16 ignored_events = PCI_EXP_SLTSTA_DLLSC ;
772+
773+ if (!ctrl -> inband_presence_disabled )
774+ ignored_events |= events & PCI_EXP_SLTSTA_PDC ;
775+
776+ events &= ~ignored_events ;
777+ pciehp_ignore_link_change (ctrl , pdev , irq , ignored_events );
741778 }
742779
743780 /*
@@ -902,31 +939,18 @@ int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe)
902939{
903940 struct controller * ctrl = to_ctrl (hotplug_slot );
904941 struct pci_dev * pdev = ctrl_dev (ctrl );
905- u16 stat_mask = 0 , ctrl_mask = 0 ;
906942 int rc ;
907943
908944 if (probe )
909945 return 0 ;
910946
911947 down_write_nested (& ctrl -> reset_lock , ctrl -> depth );
912948
913- if (!ATTN_BUTTN (ctrl )) {
914- ctrl_mask |= PCI_EXP_SLTCTL_PDCE ;
915- stat_mask |= PCI_EXP_SLTSTA_PDC ;
916- }
917- ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE ;
918- stat_mask |= PCI_EXP_SLTSTA_DLLSC ;
919-
920- pcie_write_cmd (ctrl , 0 , ctrl_mask );
921- ctrl_dbg (ctrl , "%s: SLOTCTRL %x write cmd %x\n" , __func__ ,
922- pci_pcie_cap (ctrl -> pcie -> port ) + PCI_EXP_SLTCTL , 0 );
949+ pci_hp_ignore_link_change (pdev );
923950
924951 rc = pci_bridge_secondary_bus_reset (ctrl -> pcie -> port );
925952
926- pcie_capability_write_word (pdev , PCI_EXP_SLTSTA , stat_mask );
927- pcie_write_cmd_nowait (ctrl , ctrl_mask , ctrl_mask );
928- ctrl_dbg (ctrl , "%s: SLOTCTRL %x write cmd %x\n" , __func__ ,
929- pci_pcie_cap (ctrl -> pcie -> port ) + PCI_EXP_SLTCTL , ctrl_mask );
953+ pci_hp_unignore_link_change (pdev );
930954
931955 up_write (& ctrl -> reset_lock );
932956 return rc ;
0 commit comments