mirror of https://github.com/OpenIPC/firmware.git
100 lines
3.0 KiB
Diff
100 lines
3.0 KiB
Diff
diff -drupN a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
|
|
--- a/arch/arm64/kernel/pci.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/arch/arm64/kernel/pci.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -23,11 +23,94 @@
|
|
#include <linux/slab.h>
|
|
|
|
/*
|
|
+ * If the bus contains any of these devices, then we must not turn on
|
|
+ * parity checking of any kind. Currently this is CyberPro 20x0 only.
|
|
+ */
|
|
+static inline int pdev_bad_for_parity(struct pci_dev *dev)
|
|
+{
|
|
+ return ((dev->vendor == PCI_VENDOR_ID_INTERG &&
|
|
+ (dev->device == PCI_DEVICE_ID_INTERG_2000 ||
|
|
+ dev->device == PCI_DEVICE_ID_INTERG_2010)) ||
|
|
+ (dev->vendor == PCI_VENDOR_ID_ITE &&
|
|
+ dev->device == PCI_DEVICE_ID_ITE_8152));
|
|
+
|
|
+}
|
|
+
|
|
+/*
|
|
* Called after each bus is probed, but before its children are examined
|
|
*/
|
|
void pcibios_fixup_bus(struct pci_bus *bus)
|
|
{
|
|
- /* nothing to do, expected to be removed in the future */
|
|
+ struct pci_dev *dev;
|
|
+ u16 features = PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK;
|
|
+
|
|
+ /*
|
|
+ * Walk the devices on this bus, working out what we can
|
|
+ * and can't support.
|
|
+ */
|
|
+ list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
+ u16 status;
|
|
+
|
|
+ pci_read_config_word(dev, PCI_STATUS, &status);
|
|
+
|
|
+ /*
|
|
+ * If any device on this bus does not support fast back
|
|
+ * to back transfers, then the bus as a whole is not able
|
|
+ * to support them. Having fast back to back transfers
|
|
+ * on saves us one PCI cycle per transaction.
|
|
+ */
|
|
+ if (!(status & PCI_STATUS_FAST_BACK))
|
|
+ features &= ~PCI_COMMAND_FAST_BACK;
|
|
+
|
|
+ if (pdev_bad_for_parity(dev))
|
|
+ features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
|
|
+
|
|
+ switch (dev->class >> 8) {
|
|
+ case PCI_CLASS_BRIDGE_PCI:
|
|
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status);
|
|
+ status |= PCI_BRIDGE_CTL_PARITY|PCI_BRIDGE_CTL_MASTER_ABORT;
|
|
+ status &= ~(PCI_BRIDGE_CTL_BUS_RESET|PCI_BRIDGE_CTL_FAST_BACK);
|
|
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status);
|
|
+ break;
|
|
+
|
|
+ case PCI_CLASS_BRIDGE_CARDBUS:
|
|
+ pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, &status);
|
|
+ status |= PCI_CB_BRIDGE_CTL_PARITY|PCI_CB_BRIDGE_CTL_MASTER_ABORT;
|
|
+ pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, status);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Now walk the devices again, this time setting them up.
|
|
+ */
|
|
+ list_for_each_entry(dev, &bus->devices, bus_list) {
|
|
+ u16 cmd;
|
|
+
|
|
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
|
+ cmd |= features;
|
|
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
|
|
+
|
|
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
|
|
+ L1_CACHE_BYTES >> 2);
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Propagate the flags to the PCI bridge.
|
|
+ */
|
|
+ if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
|
|
+ if (features & PCI_COMMAND_FAST_BACK)
|
|
+ bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK;
|
|
+ if (features & PCI_COMMAND_PARITY)
|
|
+ bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Report what we did for this bus
|
|
+ */
|
|
+ pr_info("PCI: bus%d: Fast back to back transfers %sabled\n",
|
|
+ bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis");
|
|
+
|
|
}
|
|
|
|
/*
|