Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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.com
Signed-off-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Rajat Jain and committed by
Bjorn Helgaas
4353594e 0cf948aa

+9 -8
+8 -8
drivers/pci/pci.c
··· 1556 1556 { 1557 1557 int ltr; 1558 1558 struct pci_cap_saved_state *save_state; 1559 - u16 *cap; 1559 + u32 *cap; 1560 1560 1561 1561 if (!pci_is_pcie(dev)) 1562 1562 return; ··· 1571 1571 return; 1572 1572 } 1573 1573 1574 - cap = (u16 *)&save_state->cap.data[0]; 1575 - pci_read_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap++); 1576 - pci_read_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, cap++); 1574 + /* Some broken devices only support dword access to LTR */ 1575 + cap = &save_state->cap.data[0]; 1576 + pci_read_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, cap); 1577 1577 } 1578 1578 1579 1579 static void pci_restore_ltr_state(struct pci_dev *dev) 1580 1580 { 1581 1581 struct pci_cap_saved_state *save_state; 1582 1582 int ltr; 1583 - u16 *cap; 1583 + u32 *cap; 1584 1584 1585 1585 save_state = pci_find_saved_ext_cap(dev, PCI_EXT_CAP_ID_LTR); 1586 1586 ltr = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR); 1587 1587 if (!save_state || !ltr) 1588 1588 return; 1589 1589 1590 - cap = (u16 *)&save_state->cap.data[0]; 1591 - pci_write_config_word(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap++); 1592 - pci_write_config_word(dev, ltr + PCI_LTR_MAX_NOSNOOP_LAT, *cap++); 1590 + /* Some broken devices only support dword access to LTR */ 1591 + cap = &save_state->cap.data[0]; 1592 + pci_write_config_dword(dev, ltr + PCI_LTR_MAX_SNOOP_LAT, *cap); 1593 1593 } 1594 1594 1595 1595 /**
+1
drivers/pci/pcie/aspm.c
··· 496 496 encode_l12_threshold(l1_2_threshold, &scale, &value); 497 497 ctl1 |= t_common_mode << 8 | scale << 29 | value << 16; 498 498 499 + /* Some broken devices only support dword access to L1 SS */ 499 500 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, &pctl1); 500 501 pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, &pctl2); 501 502 pci_read_config_dword(child, child->l1ss + PCI_L1SS_CTL1, &cctl1);