Skip to content

Commit 95361af

Browse files
alanpeteradvijay-suman
authored andcommitted
PCI: pciehp: Add quirk to handle spurious DLLSC on a x4x4 SSD
When an Intel P5608 SSD is bifurcated into x4x4 mode, and the upstream ports both support hotplugging on each respective x4 device, a slot management system for the SSD requires both x4 slots to have power removed via sysfs (echo 0 > slot/N/power), from the OS before it can safely turn-off physical power for the whole x8 device. The implications are that slot status will display powered off and link inactive statuses for the x4 devices where the devices are actually powered until both ports have powered off. The issue with the SSD manifests when power is removed from the first-half and then the second-half. During the first-half removal, slot status shows the slot as powered-down and link-inactive, while internal power and link remain active while waiting for the second-half to have power removed. When power is then removed from the second-half, the first-half starts shutdown sequence and will trigger a DLLSC event. This is misinterpreted as an enabling event and causes the first-half to be re-enabled. The spurious enable can be resolved by ignoring link status change events when no link is active when in the off state. This patch adds a quirk for specific P5608 SSDs which have been tested for compatibility. Signed-off-by: Jon Derrick <[email protected]> Signed-off-by: James Puthukattukaran <[email protected]> Signed-off-by: Thomas Tai <[email protected]> Reviewed-by: John Donnelly <[email protected]> Reviewed-by: Jack Vogel <[email protected]> Reviewed-by: Henry Willard <[email protected]> (cherry picked from commit ee7633b0ca00aca2bc4f9c7632fe5abb88a9bb7e) Signed-off-by: Jack Vogel <[email protected]> Orabug: 36797601 (hand-merged) Signed-off-by: Alan Adamson <[email protected]> Reviewed-by: Himanshu Madhani <[email protected]>
1 parent 881ccfc commit 95361af

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

drivers/pci/hotplug/pciehp_ctrl.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ void pciehp_handle_disable_request(struct controller *ctrl)
239239
void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
240240
{
241241
int present, link_active;
242+
struct pci_dev *pdev = ctrl->pcie->port;
242243

243244
/*
244245
* If the slot is on and presence or link has changed, turn it off.
@@ -287,6 +288,13 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
287288
cancel_delayed_work(&ctrl->button_work);
288289
fallthrough;
289290
case OFF_STATE:
291+
/* Look at comment for quirk_shared_slot function */
292+
if (pdev->shared_pcc_and_link_slot &&
293+
(events & PCI_EXP_SLTSTA_DLLSC) && !link_active) {
294+
mutex_unlock(&ctrl->state_lock);
295+
pdev->shared_pcc_and_link_slot = false;
296+
break;
297+
}
290298
ctrl->state = POWERON_STATE;
291299
mutex_unlock(&ctrl->state_lock);
292300
if (present)

drivers/pci/quirks.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6298,3 +6298,36 @@ static void pci_mask_replay_timer_timeout(struct pci_dev *pdev)
62986298
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9750, pci_mask_replay_timer_timeout);
62996299
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_GLI, 0x9755, pci_mask_replay_timer_timeout);
63006300
#endif
6301+
#ifdef CONFIG_HOTPLUG_PCI_PCIE
6302+
/*
6303+
* This is an Intel NVMe SSD which sits in a x8 pciehp slot but is bifurcated
6304+
* as a x4x4 and manifests as two slots with respect to PCIe hot plug register
6305+
* states. However, the hotplug controller treats these slots as a single x8
6306+
* slot for link and power. Either one of the two slots can be powered down
6307+
* separately and the slot status will show negative power and link states, but
6308+
* internal power and link will be active until the last of the two slots is
6309+
* powered down. When the last of the two x4 slots is turned off, power and
6310+
* link will be turned off for the x8 slot by the HP controller. This
6311+
* configuration causes some interesting behavior in bringup sequence
6312+
*
6313+
* When the second slot is powered off to remove the card, this will cause the
6314+
* link to go down for both x4 slots. So, the x4 that is already powered down
6315+
* earlier will see a DLLSC event and attempt to bring itself up (card present,
6316+
* link change event, link state is down). Special handling is required in
6317+
* pciehp_handle_presence_or_link_change to prevent this unintended bring up
6318+
*/
6319+
static void quirk_shared_pcc_and_link_slot(struct pci_dev *pdev)
6320+
{
6321+
struct pci_dev *parent = pci_upstream_bridge(pdev);
6322+
6323+
if (parent && pdev->subsystem_vendor == 0x108e) {
6324+
switch (pdev->subsystem_device) {
6325+
/* P5608 */
6326+
case 0x487d:
6327+
case 0x488d:
6328+
parent->shared_pcc_and_link_slot = 1;
6329+
}
6330+
}
6331+
}
6332+
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0b60, quirk_shared_pcc_and_link_slot);
6333+
#endif /* CONFIG_HOTPLUG_PCI_PCIE */

include/linux/pci.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ struct pci_dev {
349349
u8 msi_cap; /* MSI capability offset */
350350
u8 msix_cap; /* MSI-X capability offset */
351351
u8 pcie_mpss:3; /* PCIe Max Payload Size Supported */
352+
#ifdef CONFIG_HOTPLUG_PCI_PCIE
353+
u8 shared_pcc_and_link_slot:1; /* two "slots" sharing link/power */
354+
#endif
352355
u8 rom_base_reg; /* Config register controlling ROM */
353356
u8 pin; /* Interrupt pin this device uses */
354357
u16 pcie_flags_reg; /* Cached PCIe Capabilities Register */

0 commit comments

Comments
 (0)