未验证 提交 10fc7c4a 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!496 [sync] PR-448: LoongArch: fix some pci problems

Merge Pull Request from: @openeuler-sync-bot 
 

Origin pull request: 
https://gitee.com/openeuler/kernel/pulls/448 
 
fix some pci/pcie problems of LS7A.
After apply this PR and https://gitee.com/openeuler/kernel/pulls/476
, the following test passed:
1. boot 3A5000+7A2000 machine with integrated GPU
2. SUCCESS to login with tty0
3. echo mem >/sys/power/state
4. press powerbutton
5. machine resumed success 
 
Link:https://gitee.com/openeuler/kernel/pulls/496 

Reviewed-by: Guo Dongtai <guodongtai@kylinos.cn> 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Signed-off-by: Zheng Zengkai <zhengzengkai@huawei.com> 
...@@ -26,12 +26,14 @@ void pcibios_add_bus(struct pci_bus *bus) ...@@ -26,12 +26,14 @@ void pcibios_add_bus(struct pci_bus *bus)
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{ {
struct pci_config_window *cfg = bridge->bus->sysdata; if (!acpi_disabled) {
struct acpi_device *adev = to_acpi_device(cfg->parent); struct pci_config_window *cfg = bridge->bus->sysdata;
struct device *bus_dev = &bridge->bus->dev; struct acpi_device *adev = to_acpi_device(cfg->parent);
struct device *bus_dev = &bridge->bus->dev;
ACPI_COMPANION_SET(&bridge->dev, adev); ACPI_COMPANION_SET(&bridge->dev, adev);
set_dev_node(bus_dev, pa_to_nid(cfg->res.start)); set_dev_node(bus_dev, pa_to_nid(cfg->res.start));
}
return 0; return 0;
} }
...@@ -210,9 +212,11 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci) ...@@ -210,9 +212,11 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
if (status > 0) { if (status > 0) {
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (entry->res->flags & IORESOURCE_MEM) { if (entry->res->flags & IORESOURCE_MEM) {
entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40); if(!entry->offset) {
entry->res->start |= entry->offset; entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40);
entry->res->end |= entry->offset; entry->res->start |= entry->offset;
entry->res->end |= entry->offset;
}
} }
} }
return status; return status;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/pci_ids.h> #include <linux/pci_ids.h>
#include <linux/pci-acpi.h> #include <linux/pci-acpi.h>
#include <linux/pci-ecam.h> #include <linux/pci-ecam.h>
#include <linux/vgaarb.h>
#include "../pci.h" #include "../pci.h"
...@@ -19,6 +20,12 @@ ...@@ -19,6 +20,12 @@
#define DEV_PCIE_PORT_1 0x7a19 #define DEV_PCIE_PORT_1 0x7a19
#define DEV_PCIE_PORT_2 0x7a29 #define DEV_PCIE_PORT_2 0x7a29
#define DEV_PCIE_PORT_4 0x7a39
#define DEV_PCIE_PORT_5 0x7a49
#define DEV_PCIE_PORT_6 0x7a59
#define DEV_PCIE_PORT_7 0x7a69
#define DEV_LS2K_APB 0x7a02 #define DEV_LS2K_APB 0x7a02
#define DEV_LS7A_GMAC 0x7a03 #define DEV_LS7A_GMAC 0x7a03
#define DEV_LS7A_DC1 0x7a06 #define DEV_LS7A_DC1 0x7a06
...@@ -76,6 +83,20 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, ...@@ -76,6 +83,20 @@ 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);
static void loongson_d3_quirk(struct pci_dev *pdev)
{
pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
pdev->no_d1d2 = 1;
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_4, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_5, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_6, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_PCIE_PORT_7, loongson_d3_quirk);
static void loongson_mrrs_quirk(struct pci_dev *pdev) static void loongson_mrrs_quirk(struct pci_dev *pdev)
{ {
/* /*
...@@ -137,6 +158,91 @@ static void loongson_ohci_quirk(struct pci_dev *dev) ...@@ -137,6 +158,91 @@ static void loongson_ohci_quirk(struct pci_dev *dev)
} }
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_OHCI, loongson_ohci_quirk); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, DEV_LS7A_OHCI, loongson_ohci_quirk);
static void loongson_display_quirk(struct pci_dev *dev)
{
u32 val;
u64 mask, size;
u64 max_size = 0;
int i, num;
struct pci_bus *bus = dev->bus;
if (!dev->bus->number) {
if (!(dev->vendor == PCI_VENDOR_ID_LOONGSON && dev->device == 0x7a25))
return;
} else {
while (!pci_is_root_bus(bus->parent))
bus = bus->parent;
/* ensure slot is 7a2000 */
if (bus->self->vendor != PCI_VENDOR_ID_LOONGSON || bus->self->device < 0x7a39)
return;
}
max_size = 0;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (dev->resource[i].flags & IORESOURCE_MEM) {
size = dev->resource[i].end - dev->resource[i].start;
if (size > max_size) {
max_size = size;
num = i;
}
}
}
mask = ~(dev->resource[num].end - dev->resource[num].start);
val = (dev->resource[num].start >> (24 - 16)) | ((mask >> 24) & 0xffff);
writel(val, (volatile void *)0x80000efdfb000174UL);
writel(0x80000000, (volatile void *)0x80000efdfb000170UL);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, 0x7a25, loongson_display_quirk);
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
PCI_BASE_CLASS_DISPLAY, 16, loongson_display_quirk);
static void pci_fixup_aspeed(struct pci_dev *pdev)
{
struct pci_dev *bridge;
struct pci_bus *bus;
struct pci_dev *vdevp = NULL;
u16 config;
bus = pdev->bus;
bridge = bus->self;
/* Is VGA routed to us? */
if (bridge && (pci_is_bridge(bridge))) {
pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &config);
/* Yes, this bridge is PCI bridge-to-bridge spec compliant,
* just return!
*/
if (config & PCI_BRIDGE_CTL_VGA)
return;
dev_warn(&pdev->dev, "VGA bridge control is not enabled\n");
}
/* Just return if the system already have a default device */
if (vga_default_device())
return;
/* No default vga device */
while ((vdevp = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, vdevp))) {
if (vdevp->vendor != 0x1a03) {
/* Have other vga devcie in the system, do nothing */
dev_info(&pdev->dev,
"Another boot vga device: 0x%x:0x%x\n",
vdevp->vendor, vdevp->device);
return;
}
}
vga_set_default_device(pdev);
dev_info(&pdev->dev,
"Boot vga device set as 0x%x:0x%x\n",
pdev->vendor, pdev->device);
}
DECLARE_PCI_FIXUP_CLASS_FINAL(0x1a03, 0x2000,
PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_aspeed);
static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus) static struct loongson_pci *pci_bus_to_loongson_pci(struct pci_bus *bus)
{ {
struct pci_config_window *cfg; struct pci_config_window *cfg;
...@@ -216,6 +322,36 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus, ...@@ -216,6 +322,36 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
return NULL; return NULL;
} }
static int pci_loongson_config_read(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *val)
{
void __iomem *addr;
addr = bus->ops->map_bus(bus, devfn, where);
if (!addr) {
*val = ~0;
return PCIBIOS_DEVICE_NOT_FOUND;
}
if (size == 1)
*val = readb(addr);
else if (size == 2)
*val = readw(addr);
else
*val = readl(addr);
/*
* fix some pcie card not scanning properly when bus number is
* inconsistent during firmware and kernel scan phases.
*/
if (*val == 0x0 && where == PCI_VENDOR_ID) {
writel(*val, addr);
*val = readl(addr);
}
return PCIBIOS_SUCCESSFUL;
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
...@@ -239,7 +375,7 @@ static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ...@@ -239,7 +375,7 @@ static int loongson_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
/* LS2K/LS7A accept 8/16/32-bit PCI config operations */ /* LS2K/LS7A accept 8/16/32-bit PCI config operations */
static struct pci_ops loongson_pci_ops = { static struct pci_ops loongson_pci_ops = {
.map_bus = pci_loongson_map_bus, .map_bus = pci_loongson_map_bus,
.read = pci_generic_config_read, .read = pci_loongson_config_read,
.write = pci_generic_config_write, .write = pci_generic_config_write,
}; };
...@@ -282,6 +418,7 @@ static int loongson_pci_probe(struct platform_device *pdev) ...@@ -282,6 +418,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct pci_host_bridge *bridge; struct pci_host_bridge *bridge;
struct resource *regs; struct resource *regs;
unsigned int num = 0;
if (!node) if (!node)
return -ENODEV; return -ENODEV;
...@@ -306,7 +443,9 @@ static int loongson_pci_probe(struct platform_device *pdev) ...@@ -306,7 +443,9 @@ static int loongson_pci_probe(struct platform_device *pdev)
} }
if (priv->data->flags & FLAG_CFG1) { if (priv->data->flags & FLAG_CFG1) {
regs = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (priv->cfg0_base)
num = 1;
regs = platform_get_resource(pdev, IORESOURCE_MEM, num);
if (!regs) if (!regs)
dev_info(dev, "missing mem resource for cfg1\n"); dev_info(dev, "missing mem resource for cfg1\n");
else { else {
...@@ -363,7 +502,7 @@ const struct pci_ecam_ops loongson_pci_ecam_ops = { ...@@ -363,7 +502,7 @@ const struct pci_ecam_ops loongson_pci_ecam_ops = {
.init = loongson_pci_ecam_init, .init = loongson_pci_ecam_init,
.pci_ops = { .pci_ops = {
.map_bus = pci_loongson_map_bus, .map_bus = pci_loongson_map_bus,
.read = pci_generic_config_read, .read = pci_loongson_config_read,
.write = pci_generic_config_write, .write = pci_generic_config_write,
} }
}; };
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <linux/aer.h> #include <linux/aer.h>
#ifdef CONFIG_MACH_LOONGSON64
#include <linux/suspend.h>
#endif
#include "pci.h" #include "pci.h"
DEFINE_MUTEX(pci_slot_mutex); DEFINE_MUTEX(pci_slot_mutex);
...@@ -147,6 +150,15 @@ static bool pci_bridge_d3_disable; ...@@ -147,6 +150,15 @@ static bool pci_bridge_d3_disable;
/* Force bridge_d3 for all PCIe ports */ /* Force bridge_d3 for all PCIe ports */
static bool pci_bridge_d3_force; static bool pci_bridge_d3_force;
#ifdef CONFIG_MACH_LOONGSON64
#ifndef CONFIG_PM_SLEEP
suspend_state_t pm_suspend_target_state;
#define pm_suspend_target_state (PM_SUSPEND_ON)
#endif
#endif
static int __init pcie_port_pm_setup(char *str) static int __init pcie_port_pm_setup(char *str)
{ {
if (!strcmp(str, "off")) if (!strcmp(str, "off"))
...@@ -5750,8 +5762,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) ...@@ -5750,8 +5762,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
{ {
u16 v; u16 v;
int ret; int ret;
#ifdef CONFIG_MACH_LOONGSON64
struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
#endif
if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
return -EINVAL; return -EINVAL;
...@@ -5768,11 +5781,13 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) ...@@ -5768,11 +5781,13 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
} }
v = (ffs(rq) - 8) << 12; v = (ffs(rq) - 8) << 12;
#ifdef CONFIG_MACH_LOONGSON64
if (bridge->no_inc_mrrs) { if (pm_suspend_target_state == PM_SUSPEND_ON &&
bridge->no_inc_mrrs) {
if (rq > pcie_get_readrq(dev)) if (rq > pcie_get_readrq(dev))
return -EINVAL; return -EINVAL;
} }
#endif
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v); PCI_EXP_DEVCTL_READRQ, v);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册