Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoongArch: fix some pci problems(Pull request again) #192

Merged
8 changes: 5 additions & 3 deletions arch/loongarch/pci/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,9 +214,11 @@ 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) {
entry->offset = ci->root->mcfg_addr & GENMASK_ULL(63, 40);
entry->res->start |= entry->offset;
entry->res->end |= entry->offset;
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;
Expand Down
147 changes: 144 additions & 3 deletions drivers/pci/controller/pci-loongson.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -32,6 +33,7 @@
#define DEV_LS7A_CONF 0x7a10
#define DEV_LS7A_GNET 0x7a13
#define DEV_LS7A_EHCI 0x7a14
#define DEV_LS7A_OHCI 0x7a24
#define DEV_LS7A_DC2 0x7a36
#define DEV_LS7A_HDMI 0x7a37

Expand Down Expand Up @@ -80,6 +82,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_LS7A_PCIE_PORT3, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_LS7A_PCIE_PORT4, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_LS7A_PCIE_PORT5, loongson_d3_quirk);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_LOONGSON,
DEV_LS7A_PCIE_PORT6, loongson_d3_quirk);

/*
* Some Loongson PCIe ports have hardware limitations on their Maximum Read
* Request Size. They can't handle anything larger than this. Sane
Expand Down Expand Up @@ -163,6 +179,98 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON,
DEV_LS7A_HDMI, loongson_pci_pin_quirk);

static void loongson_ohci_quirk(struct pci_dev *dev)
{
if (dev->revision == 0x2)
dev->resource[0].start += 0x1000;
}
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;
Expand Down Expand Up @@ -242,6 +350,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;
Avenger-285714 marked this conversation as resolved.
Show resolved Hide resolved
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)
Expand All @@ -265,7 +403,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,
};

Expand Down Expand Up @@ -308,6 +446,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;
Expand All @@ -332,7 +471,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 {
Expand Down Expand Up @@ -389,7 +530,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,
}
};
Expand Down
20 changes: 18 additions & 2 deletions drivers/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
#include <asm/dma.h>
#include <linux/aer.h>
#include <linux/bitfield.h>
#ifdef CONFIG_MACH_LOONGSON64
#include <linux/suspend.h>
#endif
#include "pci.h"

DEFINE_MUTEX(pci_slot_mutex);
Expand Down Expand Up @@ -172,6 +175,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"))
Expand Down Expand Up @@ -6186,8 +6198,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;

Expand All @@ -6205,14 +6218,17 @@ 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) {
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;
}
}
#endif

ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ, v);
Expand Down