hc
2024-08-12 0517ab8c70e05fc5877c0c6dae1a5f42a16dcf88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// SPDX-License-Identifier: GPL-2.0
/*
 * Simple, generic PCI host controller driver targeting firmware-initialised
 * systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
 *
 * Copyright (C) 2014 ARM Limited
 *
 * Author: Will Deacon <will.deacon@arm.com>
 */
 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci-ecam.h>
#include <linux/platform_device.h>
 
static const struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
   .bus_shift    = 16,
   .pci_ops    = {
       .map_bus    = pci_ecam_map_bus,
       .read        = pci_generic_config_read,
       .write        = pci_generic_config_write,
   }
};
 
static bool pci_dw_valid_device(struct pci_bus *bus, unsigned int devfn)
{
   struct pci_config_window *cfg = bus->sysdata;
 
   /*
    * The Synopsys DesignWare PCIe controller in ECAM mode will not filter
    * type 0 config TLPs sent to devices 1 and up on its downstream port,
    * resulting in devices appearing multiple times on bus 0 unless we
    * filter out those accesses here.
    */
   if (bus->number == cfg->busr.start && PCI_SLOT(devfn) > 0)
       return false;
 
   return true;
}
 
static void __iomem *pci_dw_ecam_map_bus(struct pci_bus *bus,
                    unsigned int devfn, int where)
{
   if (!pci_dw_valid_device(bus, devfn))
       return NULL;
 
   return pci_ecam_map_bus(bus, devfn, where);
}
 
static const struct pci_ecam_ops pci_dw_ecam_bus_ops = {
   .bus_shift    = 20,
   .pci_ops    = {
       .map_bus    = pci_dw_ecam_map_bus,
       .read        = pci_generic_config_read,
       .write        = pci_generic_config_write,
   }
};
 
static const struct of_device_id gen_pci_of_match[] = {
   { .compatible = "pci-host-cam-generic",
     .data = &gen_pci_cfg_cam_bus_ops },
 
   { .compatible = "pci-host-ecam-generic",
     .data = &pci_generic_ecam_ops },
 
   { .compatible = "marvell,armada8k-pcie-ecam",
     .data = &pci_dw_ecam_bus_ops },
 
   { .compatible = "socionext,synquacer-pcie-ecam",
     .data = &pci_dw_ecam_bus_ops },
 
   { .compatible = "snps,dw-pcie-ecam",
     .data = &pci_dw_ecam_bus_ops },
 
   { },
};
MODULE_DEVICE_TABLE(of, gen_pci_of_match);
 
static struct platform_driver gen_pci_driver = {
   .driver = {
       .name = "pci-host-generic",
       .of_match_table = gen_pci_of_match,
   },
   .probe = pci_host_common_probe,
   .remove = pci_host_common_remove,
};
module_platform_driver(gen_pci_driver);
 
MODULE_LICENSE("GPL v2");