PCI: loongson: Limit MRRS to 256
This is a partial revert of8b3517f88f
("PCI: loongson: Prevent LS7A MRRS increases") for MIPS-based Loongson. Some MIPS Loongson systems don't support arbitrary Max_Read_Request_Size (MRRS) settings.8b3517f88f
("PCI: loongson: Prevent LS7A MRRS increases") worked around that by (1) assuming that firmware configured MRRS to the maximum supported value and (2) preventing the PCI core from increasing MRRS. Unfortunately, some firmware doesn't set that maximum MRRS correctly, which results in devices not being initialized correctly. One symptom, from the Debian report below, is this: ata4.00: exception Emask 0x0 SAct 0x20000000 SErr 0x0 action 0x6 frozen ata4.00: failed command: WRITE FPDMA QUEUED ata4.00: cmd 61/20:e8:00:f0:e1/00:00:00:00:00/40 tag 29 ncq dma 16384 out res 40/00:00:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout) ata4.00: status: { DRDY } ata4: hard resetting link Limit MRRS to 256 because MIPS Loongson with higher MRRS support is considered rare. This must be done at device enablement stage because the MRRS setting may get lost if PCI_COMMAND_MASTER on the parent bridge is cleared, and we are only sure parent bridge is enabled at this point. Fixes:8b3517f88f
("PCI: loongson: Prevent LS7A MRRS increases") Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217680 Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1035587 Link: https://lore.kernel.org/r/20231201115028.84351-1-jiaxun.yang@flygoat.com Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Huacai Chen <chenhuacai@loongson.cn> Cc: stable@vger.kernel.org
This commit is contained in:
parent
b85ea95d08
commit
ef61a04057
@ -80,13 +80,49 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
|||||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||||
DEV_LS7A_LPC, system_bus_quirk);
|
DEV_LS7A_LPC, system_bus_quirk);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some Loongson PCIe ports have hardware limitations on their Maximum Read
|
||||||
|
* Request Size. They can't handle anything larger than this. Sane
|
||||||
|
* firmware will set proper MRRS at boot, so we only need no_inc_mrrs for
|
||||||
|
* bridges. However, some MIPS Loongson firmware doesn't set MRRS properly,
|
||||||
|
* so we have to enforce maximum safe MRRS, which is 256 bytes.
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_MIPS
|
||||||
|
static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct pci_bus *bus = pdev->bus;
|
||||||
|
struct pci_dev *bridge;
|
||||||
|
static const struct pci_device_id bridge_devids[] = {
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS2K_PCIE_PORT0) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT0) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT1) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT2) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT3) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT4) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT5) },
|
||||||
|
{ PCI_VDEVICE(LOONGSON, DEV_LS7A_PCIE_PORT6) },
|
||||||
|
{ 0, },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* look for the matching bridge */
|
||||||
|
while (!pci_is_root_bus(bus)) {
|
||||||
|
bridge = bus->self;
|
||||||
|
bus = bus->parent;
|
||||||
|
|
||||||
|
if (pci_match_id(bridge_devids, bridge)) {
|
||||||
|
if (pcie_get_readrq(pdev) > 256) {
|
||||||
|
pci_info(pdev, "limiting MRRS to 256\n");
|
||||||
|
pcie_set_readrq(pdev, 256);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_set_min_mrrs_quirk);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void loongson_mrrs_quirk(struct pci_dev *pdev)
|
static void loongson_mrrs_quirk(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Some Loongson PCIe ports have h/w limitations of maximum read
|
|
||||||
* request size. They can't handle anything larger than this. So
|
|
||||||
* force this limit on any devices attached under these ports.
|
|
||||||
*/
|
|
||||||
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
|
struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
|
||||||
|
|
||||||
bridge->no_inc_mrrs = 1;
|
bridge->no_inc_mrrs = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user