Merge branch 'pci/enumeration'
- Implement portdrv .shutdown() method that calls service driver .remove() methods (which disables interrupt generation as required by .shutdown()), but doesn't disable bus mastering (which hangs on Loongson LS7A because of a hardware defect) (Huacai Chen) - Prevent MRRS increases for devices below Loongson LS7A to avoid hardware limitations (Huacai Chen) - Ignore devices with a firmware (DT/ACPI) node that says the device is disabled (Rob Herring) * pci/enumeration: PCI: Honor firmware's device disabled status PCI: loongson: Add more devices that need MRRS quirk PCI: loongson: Prevent LS7A MRRS increases PCI/portdrv: Prevent LS7A Bus Master clearing on shutdown
This commit is contained in:
commit
a17613298f
@ -15,9 +15,14 @@
|
||||
#include "../pci.h"
|
||||
|
||||
/* Device IDs */
|
||||
#define DEV_PCIE_PORT_0 0x7a09
|
||||
#define DEV_PCIE_PORT_1 0x7a19
|
||||
#define DEV_PCIE_PORT_2 0x7a29
|
||||
#define DEV_LS2K_PCIE_PORT0 0x1a05
|
||||
#define DEV_LS7A_PCIE_PORT0 0x7a09
|
||||
#define DEV_LS7A_PCIE_PORT1 0x7a19
|
||||
#define DEV_LS7A_PCIE_PORT2 0x7a29
|
||||
#define DEV_LS7A_PCIE_PORT3 0x7a39
|
||||
#define DEV_LS7A_PCIE_PORT4 0x7a49
|
||||
#define DEV_LS7A_PCIE_PORT5 0x7a59
|
||||
#define DEV_LS7A_PCIE_PORT6 0x7a69
|
||||
|
||||
#define DEV_LS2K_APB 0x7a02
|
||||
#define DEV_LS7A_GMAC 0x7a03
|
||||
@ -53,11 +58,11 @@ static void bridge_class_quirk(struct pci_dev *dev)
|
||||
dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_PCIE_PORT_0, bridge_class_quirk);
|
||||
DEV_LS7A_PCIE_PORT0, bridge_class_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_PCIE_PORT_1, bridge_class_quirk);
|
||||
DEV_LS7A_PCIE_PORT1, bridge_class_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_PCIE_PORT_2, bridge_class_quirk);
|
||||
DEV_LS7A_PCIE_PORT2, bridge_class_quirk);
|
||||
|
||||
static void system_bus_quirk(struct pci_dev *pdev)
|
||||
{
|
||||
@ -75,37 +80,33 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_LPC, system_bus_quirk);
|
||||
|
||||
static void loongson_mrrs_quirk(struct pci_dev *dev)
|
||||
static void loongson_mrrs_quirk(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_bus *bus = dev->bus;
|
||||
struct pci_dev *bridge;
|
||||
static const struct pci_device_id bridge_devids[] = {
|
||||
{ PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_0) },
|
||||
{ PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_1) },
|
||||
{ PCI_VDEVICE(LOONGSON, DEV_PCIE_PORT_2) },
|
||||
{ 0, },
|
||||
};
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* look for the matching bridge */
|
||||
while (!pci_is_root_bus(bus)) {
|
||||
bridge = bus->self;
|
||||
bus = bus->parent;
|
||||
/*
|
||||
* Some Loongson PCIe ports have a h/w limitation of
|
||||
* 256 bytes maximum read request size. They can't handle
|
||||
* anything larger than this. So force this limit on
|
||||
* any devices attached under these ports.
|
||||
*/
|
||||
if (pci_match_id(bridge_devids, bridge)) {
|
||||
if (pcie_get_readrq(dev) > 256) {
|
||||
pci_info(dev, "limiting MRRS to 256\n");
|
||||
pcie_set_readrq(dev, 256);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
bridge->no_inc_mrrs = 1;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS2K_PCIE_PORT0, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT0, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT1, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT2, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT3, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT4, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT5, loongson_mrrs_quirk);
|
||||
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,
|
||||
DEV_LS7A_PCIE_PORT6, loongson_mrrs_quirk);
|
||||
|
||||
static void loongson_pci_pin_quirk(struct pci_dev *pdev)
|
||||
{
|
||||
|
@ -6033,6 +6033,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
|
||||
{
|
||||
u16 v;
|
||||
int ret;
|
||||
struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
|
||||
|
||||
if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
|
||||
return -EINVAL;
|
||||
@ -6051,6 +6052,15 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
|
||||
|
||||
v = (ffs(rq) - 8) << 12;
|
||||
|
||||
if (bridge->no_inc_mrrs) {
|
||||
int max_mrrs = pcie_get_readrq(dev);
|
||||
|
||||
if (rq > max_mrrs) {
|
||||
pci_info(dev, "can't set Max_Read_Request_Size to %d; max is %d\n", rq, max_mrrs);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_READRQ, v);
|
||||
|
||||
|
@ -501,7 +501,6 @@ static void pcie_port_device_remove(struct pci_dev *dev)
|
||||
{
|
||||
device_for_each_child(&dev->dev, NULL, remove_iter);
|
||||
pci_free_irq_vectors(dev);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -727,6 +726,19 @@ static void pcie_portdrv_remove(struct pci_dev *dev)
|
||||
}
|
||||
|
||||
pcie_port_device_remove(dev);
|
||||
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
|
||||
static void pcie_portdrv_shutdown(struct pci_dev *dev)
|
||||
{
|
||||
if (pci_bridge_d3_possible(dev)) {
|
||||
pm_runtime_forbid(&dev->dev);
|
||||
pm_runtime_get_noresume(&dev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&dev->dev);
|
||||
}
|
||||
|
||||
pcie_port_device_remove(dev);
|
||||
}
|
||||
|
||||
static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
|
||||
@ -777,7 +789,7 @@ static struct pci_driver pcie_portdriver = {
|
||||
|
||||
.probe = pcie_portdrv_probe,
|
||||
.remove = pcie_portdrv_remove,
|
||||
.shutdown = pcie_portdrv_remove,
|
||||
.shutdown = pcie_portdrv_shutdown,
|
||||
|
||||
.err_handler = &pcie_portdrv_err_handler,
|
||||
|
||||
|
@ -1841,6 +1841,8 @@ int pci_setup_device(struct pci_dev *dev)
|
||||
|
||||
pci_set_of_node(dev);
|
||||
pci_set_acpi_fwnode(dev);
|
||||
if (dev->dev.fwnode && !fwnode_device_is_available(dev->dev.fwnode))
|
||||
return -ENODEV;
|
||||
|
||||
pci_dev_assign_slot(dev);
|
||||
|
||||
|
@ -572,6 +572,7 @@ struct pci_host_bridge {
|
||||
void *release_data;
|
||||
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
|
||||
unsigned int no_ext_tags:1; /* No Extended Tags */
|
||||
unsigned int no_inc_mrrs:1; /* No Increase MRRS */
|
||||
unsigned int native_aer:1; /* OS may use PCIe AER */
|
||||
unsigned int native_pcie_hotplug:1; /* OS may use PCIe hotplug */
|
||||
unsigned int native_shpc_hotplug:1; /* OS may use SHPC hotplug */
|
||||
|
Loading…
Reference in New Issue
Block a user