1 /*
2  * Based on Linux drivers/pci/ecam.c
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <xen/pci.h>
18 #include <xen/sched.h>
19 
20 /*
21  * Function to implement the pci_ops->map_bus method.
22  */
pci_ecam_map_bus(struct pci_host_bridge * bridge,pci_sbdf_t sbdf,uint32_t where)23 void __iomem *pci_ecam_map_bus(struct pci_host_bridge *bridge,
24                                pci_sbdf_t sbdf, uint32_t where)
25 {
26     const struct pci_config_window *cfg = bridge->cfg;
27     const struct pci_ecam_ops *ops =
28         container_of(bridge->ops, const struct pci_ecam_ops, pci_ops);
29     unsigned int devfn_shift = ops->bus_shift - 8;
30     void __iomem *base;
31     unsigned int busn = sbdf.bus;
32 
33     if ( busn < cfg->busn_start || busn > cfg->busn_end )
34         return NULL;
35 
36     busn -= cfg->busn_start;
37     base = cfg->win + (busn << ops->bus_shift);
38 
39     return base + (sbdf.devfn << devfn_shift) + where;
40 }
41 
pci_ecam_need_p2m_hwdom_mapping(struct domain * d,struct pci_host_bridge * bridge,uint64_t addr)42 bool __init pci_ecam_need_p2m_hwdom_mapping(struct domain *d,
43                                             struct pci_host_bridge *bridge,
44                                             uint64_t addr)
45 {
46     struct pci_config_window *cfg = bridge->cfg;
47 
48     /*
49      * We do not want ECAM address space to be mapped in Domain-0's p2m,
50      * so we can trap access to it.
51      */
52     return cfg->phys_addr != addr;
53 }
54 
55 /* ECAM ops */
56 const struct pci_ecam_ops pci_generic_ecam_ops = {
57     .bus_shift  = 20,
58     .pci_ops    = {
59         .map_bus                = pci_ecam_map_bus,
60         .read                   = pci_generic_config_read,
61         .write                  = pci_generic_config_write,
62         .need_p2m_hwdom_mapping = pci_ecam_need_p2m_hwdom_mapping,
63     }
64 };
65 
66 /*
67  * Local variables:
68  * mode: C
69  * c-file-style: "BSD"
70  * c-basic-offset: 4
71  * tab-width: 4
72  * indent-tabs-mode: nil
73  * End:
74  */
75