Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
0004  * Copyright (C) 2004 Intel Corp.
0005  */
0006 
0007 /*
0008  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
0009  */
0010 
0011 #include <linux/pci.h>
0012 #include <linux/init.h>
0013 #include <linux/rcupdate.h>
0014 #include <asm/e820/api.h>
0015 #include <asm/pci_x86.h>
0016 
0017 /* Assume systems with more busses have correct MCFG */
0018 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
0019 
0020 /* The base address of the last MMCONFIG device accessed */
0021 static u32 mmcfg_last_accessed_device;
0022 static int mmcfg_last_accessed_cpu;
0023 
0024 /*
0025  * Functions for accessing PCI configuration space with MMCONFIG accesses
0026  */
0027 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
0028 {
0029     struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
0030 
0031     if (cfg)
0032         return cfg->address;
0033     return 0;
0034 }
0035 
0036 /*
0037  * This is always called under pci_config_lock
0038  */
0039 static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
0040 {
0041     u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12);
0042     int cpu = smp_processor_id();
0043     if (dev_base != mmcfg_last_accessed_device ||
0044         cpu != mmcfg_last_accessed_cpu) {
0045         mmcfg_last_accessed_device = dev_base;
0046         mmcfg_last_accessed_cpu = cpu;
0047         set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
0048     }
0049 }
0050 
0051 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
0052               unsigned int devfn, int reg, int len, u32 *value)
0053 {
0054     unsigned long flags;
0055     u32 base;
0056 
0057     if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
0058 err:        *value = -1;
0059         return -EINVAL;
0060     }
0061 
0062     rcu_read_lock();
0063     base = get_base_addr(seg, bus, devfn);
0064     if (!base) {
0065         rcu_read_unlock();
0066         goto err;
0067     }
0068 
0069     raw_spin_lock_irqsave(&pci_config_lock, flags);
0070 
0071     pci_exp_set_dev_base(base, bus, devfn);
0072 
0073     switch (len) {
0074     case 1:
0075         *value = mmio_config_readb(mmcfg_virt_addr + reg);
0076         break;
0077     case 2:
0078         *value = mmio_config_readw(mmcfg_virt_addr + reg);
0079         break;
0080     case 4:
0081         *value = mmio_config_readl(mmcfg_virt_addr + reg);
0082         break;
0083     }
0084     raw_spin_unlock_irqrestore(&pci_config_lock, flags);
0085     rcu_read_unlock();
0086 
0087     return 0;
0088 }
0089 
0090 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
0091                unsigned int devfn, int reg, int len, u32 value)
0092 {
0093     unsigned long flags;
0094     u32 base;
0095 
0096     if ((bus > 255) || (devfn > 255) || (reg > 4095))
0097         return -EINVAL;
0098 
0099     rcu_read_lock();
0100     base = get_base_addr(seg, bus, devfn);
0101     if (!base) {
0102         rcu_read_unlock();
0103         return -EINVAL;
0104     }
0105 
0106     raw_spin_lock_irqsave(&pci_config_lock, flags);
0107 
0108     pci_exp_set_dev_base(base, bus, devfn);
0109 
0110     switch (len) {
0111     case 1:
0112         mmio_config_writeb(mmcfg_virt_addr + reg, value);
0113         break;
0114     case 2:
0115         mmio_config_writew(mmcfg_virt_addr + reg, value);
0116         break;
0117     case 4:
0118         mmio_config_writel(mmcfg_virt_addr + reg, value);
0119         break;
0120     }
0121     raw_spin_unlock_irqrestore(&pci_config_lock, flags);
0122     rcu_read_unlock();
0123 
0124     return 0;
0125 }
0126 
0127 const struct pci_raw_ops pci_mmcfg = {
0128     .read =     pci_mmcfg_read,
0129     .write =    pci_mmcfg_write,
0130 };
0131 
0132 int __init pci_mmcfg_arch_init(void)
0133 {
0134     printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
0135     raw_pci_ext_ops = &pci_mmcfg;
0136     return 1;
0137 }
0138 
0139 void __init pci_mmcfg_arch_free(void)
0140 {
0141 }
0142 
0143 int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
0144 {
0145     return 0;
0146 }
0147 
0148 void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
0149 {
0150     unsigned long flags;
0151 
0152     /* Invalidate the cached mmcfg map entry. */
0153     raw_spin_lock_irqsave(&pci_config_lock, flags);
0154     mmcfg_last_accessed_device = 0;
0155     raw_spin_unlock_irqrestore(&pci_config_lock, flags);
0156 }