未验证 提交 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)
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
if (!acpi_disabled) {
struct pci_config_window *cfg = bridge->bus->sysdata;
struct acpi_device *adev = to_acpi_device(cfg->parent);
struct device *bus_dev = &bridge->bus->dev;
ACPI_COMPANION_SET(&bridge->dev, adev);
set_dev_node(bus_dev, pa_to_nid(cfg->res.start));
}
return 0;
}
......@@ -210,11 +212,13 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
if (status > 0) {
resource_list_for_each_entry_safe(entry, tmp, &ci->resources) {
if (entry->res->flags & IORESOURCE_MEM) {
if(!entry->offset) {
entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40);
entry->res->start |= entry->offset;
entry->res->end |= entry->offset;
}
}
}
return status;
}
......
......@@ -11,6 +11,7 @@
#include <linux/pci_ids.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/vgaarb.h>
#include "../pci.h"
......@@ -19,6 +20,12 @@
#define DEV_PCIE_PORT_1 0x7a19
#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_LS7A_GMAC 0x7a03
#define DEV_LS7A_DC1 0x7a06
......@@ -76,6 +83,20 @@ 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_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)
{
/*
......@@ -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);
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)
{
struct pci_config_window *cfg;
......@@ -216,6 +322,36 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,
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
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 */
static struct pci_ops loongson_pci_ops = {
.map_bus = pci_loongson_map_bus,
.read = pci_generic_config_read,
.read = pci_loongson_config_read,
.write = pci_generic_config_write,
};
......@@ -282,6 +418,7 @@ static int loongson_pci_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
struct pci_host_bridge *bridge;
struct resource *regs;
unsigned int num = 0;
if (!node)
return -ENODEV;
......@@ -306,7 +443,9 @@ static int loongson_pci_probe(struct platform_device *pdev)
}
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)
dev_info(dev, "missing mem resource for cfg1\n");
else {
......@@ -363,7 +502,7 @@ const struct pci_ecam_ops loongson_pci_ecam_ops = {
.init = loongson_pci_ecam_init,
.pci_ops = {
.map_bus = pci_loongson_map_bus,
.read = pci_generic_config_read,
.read = pci_loongson_config_read,
.write = pci_generic_config_write,
}
};
......
......@@ -31,6 +31,9 @@
#include <linux/vmalloc.h>
#include <asm/dma.h>
#include <linux/aer.h>
#ifdef CONFIG_MACH_LOONGSON64
#include <linux/suspend.h>
#endif
#include "pci.h"
DEFINE_MUTEX(pci_slot_mutex);
......@@ -147,6 +150,15 @@ static bool pci_bridge_d3_disable;
/* Force bridge_d3 for all PCIe ports */
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)
{
if (!strcmp(str, "off"))
......@@ -5750,8 +5762,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
{
u16 v;
int ret;
#ifdef CONFIG_MACH_LOONGSON64
struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
#endif
if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
return -EINVAL;
......@@ -5768,11 +5781,13 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
}
v = (ffs(rq) - 8) << 12;
if (bridge->no_inc_mrrs) {
#ifdef CONFIG_MACH_LOONGSON64
if (pm_suspend_target_state == PM_SUSPEND_ON &&
bridge->no_inc_mrrs) {
if (rq > pcie_get_readrq(dev))
return -EINVAL;
}
#endif
ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册