~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/pci/mmconfig_64.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
  3  *
  4  * This is an 64bit optimized version that always keeps the full mmconfig
  5  * space mapped. This allows lockless config space operation.
  6  */
  7 
  8 #include <linux/pci.h>
  9 #include <linux/init.h>
 10 #include <linux/acpi.h>
 11 #include <linux/bitmap.h>
 12 #include <linux/rcupdate.h>
 13 #include <asm/e820.h>
 14 #include <asm/pci_x86.h>
 15 
 16 #define PREFIX "PCI: "
 17 
 18 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
 19 {
 20         struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
 21 
 22         if (cfg && cfg->virt)
 23                 return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
 24         return NULL;
 25 }
 26 
 27 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
 28                           unsigned int devfn, int reg, int len, u32 *value)
 29 {
 30         char __iomem *addr;
 31 
 32         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
 33         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
 34 err:            *value = -1;
 35                 return -EINVAL;
 36         }
 37 
 38         rcu_read_lock();
 39         addr = pci_dev_base(seg, bus, devfn);
 40         if (!addr) {
 41                 rcu_read_unlock();
 42                 goto err;
 43         }
 44 
 45         switch (len) {
 46         case 1:
 47                 *value = mmio_config_readb(addr + reg);
 48                 break;
 49         case 2:
 50                 *value = mmio_config_readw(addr + reg);
 51                 break;
 52         case 4:
 53                 *value = mmio_config_readl(addr + reg);
 54                 break;
 55         }
 56         rcu_read_unlock();
 57 
 58         return 0;
 59 }
 60 
 61 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
 62                            unsigned int devfn, int reg, int len, u32 value)
 63 {
 64         char __iomem *addr;
 65 
 66         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
 67         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
 68                 return -EINVAL;
 69 
 70         rcu_read_lock();
 71         addr = pci_dev_base(seg, bus, devfn);
 72         if (!addr) {
 73                 rcu_read_unlock();
 74                 return -EINVAL;
 75         }
 76 
 77         switch (len) {
 78         case 1:
 79                 mmio_config_writeb(addr + reg, value);
 80                 break;
 81         case 2:
 82                 mmio_config_writew(addr + reg, value);
 83                 break;
 84         case 4:
 85                 mmio_config_writel(addr + reg, value);
 86                 break;
 87         }
 88         rcu_read_unlock();
 89 
 90         return 0;
 91 }
 92 
 93 const struct pci_raw_ops pci_mmcfg = {
 94         .read =         pci_mmcfg_read,
 95         .write =        pci_mmcfg_write,
 96 };
 97 
 98 static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
 99 {
100         void __iomem *addr;
101         u64 start, size;
102         int num_buses;
103 
104         start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
105         num_buses = cfg->end_bus - cfg->start_bus + 1;
106         size = PCI_MMCFG_BUS_OFFSET(num_buses);
107         addr = ioremap_nocache(start, size);
108         if (addr)
109                 addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
110         return addr;
111 }
112 
113 int __init pci_mmcfg_arch_init(void)
114 {
115         struct pci_mmcfg_region *cfg;
116 
117         list_for_each_entry(cfg, &pci_mmcfg_list, list)
118                 if (pci_mmcfg_arch_map(cfg)) {
119                         pci_mmcfg_arch_free();
120                         return 0;
121                 }
122 
123         raw_pci_ext_ops = &pci_mmcfg;
124 
125         return 1;
126 }
127 
128 void __init pci_mmcfg_arch_free(void)
129 {
130         struct pci_mmcfg_region *cfg;
131 
132         list_for_each_entry(cfg, &pci_mmcfg_list, list)
133                 pci_mmcfg_arch_unmap(cfg);
134 }
135 
136 int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
137 {
138         cfg->virt = mcfg_ioremap(cfg);
139         if (!cfg->virt) {
140                 pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
141                 return -ENOMEM;
142         }
143 
144         return 0;
145 }
146 
147 void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
148 {
149         if (cfg && cfg->virt) {
150                 iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
151                 cfg->virt = NULL;
152         }
153 }
154 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp