Unverified Commit 8c6c3cde authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!448 LoongArch: fix some pci problems

Merge Pull Request from: @Hongchen_Zhang 
 
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/448

 

Reviewed-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
Reviewed-by: default avatarGuo Dongtai <guodongtai@kylinos.cn>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents cfa7d46e a62d9cc0
Loading
Loading
Loading
Loading
+12 −8
Original line number Diff line number Diff line
@@ -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;
	}

+142 −3
Original line number Diff line number Diff line
@@ -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,
	}
};
+18 −3
Original line number Diff line number Diff line
@@ -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);