Commit 4353594e authored by Rajat Jain's avatar Rajat Jain Committed by Bjorn Helgaas

PCI: Use DWORD accesses for LTR, L1 SS to avoid erratum

Some devices have an erratum such that they only support DWORD accesses to
some registers.  E.g., this Bayhub O2 device ([VID:DID] = [0x1217:0x8621])
only supports DWORD accesses to LTR latency registers and L1 PM substates
control registers:

  https://github.com/rajatxjain/public_shared/blob/main/OZ711LV2_appnote.pdf

The L1 PM substate control registers are DWORD sized, and hence their
access in the kernel is already DWORD sized, so we don't need to do
anything for them.

However, the LTR registers being WORD sized, are in need of a solution.
Convert the WORD sized accesses to these registers into DWORD sized
accesses while saving and restoring them.

Link: https://lore.kernel.org/r/20211222012105.3438916-1-rajatja@google.comSigned-off-by: default avatarRajat Jain <rajatja@google.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 0cf948aa
......@@ -1556,7 +1556,7 @@ static void pci_save_ltr_state(struct pci_dev *dev)
{
int ltr;
struct pci_cap_saved_state *save_state;
u16 *cap;
u32 *cap;
if (!pci_is_pcie(dev))
return;
......@@ -1571,25 +1571,25 @@ static void pci_save_ltr_state(struct pci_dev *dev)
return;
}
cap = (u16 *)&save_state->cap.data[0];
pci_read_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap++);
pci_read_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, cap++);
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap);
}
static void pci_restore_ltr_state(struct pci_dev *dev)
{
struct pci_cap_saved_state *save_state;
int ltr;
u16 *cap;
u32 *cap;
save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR);
ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
if (!save_state || !ltr)
return;
cap = (u16 *)&save_state->cap.data[0];
pci_write_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap++);
pci_write_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, *cap++);
/* Some broken devices only support dword access to LTR */
cap = &save_state->cap.data[0];
pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap);
}
/**
......
......@@ -496,6 +496,7 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link,
encode_l12_threshold(l1_2_threshold, &scale, &value);
ctl1 |= t_common_mode << 8 | scale << 29 | value << 16;
/* Some broken devices only support dword access to L1 SS */
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1);
pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2);
pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment