Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * PCIe host controller driver for Amazon's Annapurna Labs IP (used in chips
4 * such as Graviton and Alpine)
5 *
6 * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
7 *
8 * Author: Jonathan Chocron <jonnyc@amazon.com>
9 */
10
11#include <linux/pci.h>
12#include <linux/pci-ecam.h>
13#include <linux/pci-acpi.h>
14#include "../../pci.h"
15
16#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
17
18struct al_pcie_acpi {
19 void __iomem *dbi_base;
20};
21
22static void __iomem *al_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
23 int where)
24{
25 struct pci_config_window *cfg = bus->sysdata;
26 struct al_pcie_acpi *pcie = cfg->priv;
27 void __iomem *dbi_base = pcie->dbi_base;
28
29 if (bus->number == cfg->busr.start) {
30 /*
31 * The DW PCIe core doesn't filter out transactions to other
32 * devices/functions on the root bus num, so we do this here.
33 */
34 if (PCI_SLOT(devfn) > 0)
35 return NULL;
36 else
37 return dbi_base + where;
38 }
39
40 return pci_ecam_map_bus(bus, devfn, where);
41}
42
43static int al_pcie_init(struct pci_config_window *cfg)
44{
45 struct device *dev = cfg->parent;
46 struct acpi_device *adev = to_acpi_device(dev);
47 struct acpi_pci_root *root = acpi_driver_data(adev);
48 struct al_pcie_acpi *al_pcie;
49 struct resource *res;
50 int ret;
51
52 al_pcie = devm_kzalloc(dev, sizeof(*al_pcie), GFP_KERNEL);
53 if (!al_pcie)
54 return -ENOMEM;
55
56 res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
57 if (!res)
58 return -ENOMEM;
59
60 ret = acpi_get_rc_resources(dev, "AMZN0001", root->segment, res);
61 if (ret) {
62 dev_err(dev, "can't get rc dbi base address for SEG %d\n",
63 root->segment);
64 return ret;
65 }
66
67 dev_dbg(dev, "Root port dbi res: %pR\n", res);
68
69 al_pcie->dbi_base = devm_pci_remap_cfg_resource(dev, res);
70 if (IS_ERR(al_pcie->dbi_base)) {
71 long err = PTR_ERR(al_pcie->dbi_base);
72
73 dev_err(dev, "couldn't remap dbi base %pR (err:%ld)\n",
74 res, err);
75 return err;
76 }
77
78 cfg->priv = al_pcie;
79
80 return 0;
81}
82
83struct pci_ecam_ops al_pcie_ops = {
84 .bus_shift = 20,
85 .init = al_pcie_init,
86 .pci_ops = {
87 .map_bus = al_pcie_map_bus,
88 .read = pci_generic_config_read,
89 .write = pci_generic_config_write,
90 }
91};
92
93#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */