root/arch/x86/pci/mmconfig_32.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_base_addr
  2. pci_exp_set_dev_base
  3. pci_mmcfg_read
  4. pci_mmcfg_write
  5. pci_mmcfg_arch_init
  6. pci_mmcfg_arch_free
  7. pci_mmcfg_arch_map
  8. pci_mmcfg_arch_unmap

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
   4  * Copyright (C) 2004 Intel Corp.
   5  */
   6 
   7 /*
   8  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
   9  */
  10 
  11 #include <linux/pci.h>
  12 #include <linux/init.h>
  13 #include <linux/rcupdate.h>
  14 #include <asm/e820/api.h>
  15 #include <asm/pci_x86.h>
  16 
  17 /* Assume systems with more busses have correct MCFG */
  18 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
  19 
  20 /* The base address of the last MMCONFIG device accessed */
  21 static u32 mmcfg_last_accessed_device;
  22 static int mmcfg_last_accessed_cpu;
  23 
  24 /*
  25  * Functions for accessing PCI configuration space with MMCONFIG accesses
  26  */
  27 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
  28 {
  29         struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
  30 
  31         if (cfg)
  32                 return cfg->address;
  33         return 0;
  34 }
  35 
  36 /*
  37  * This is always called under pci_config_lock
  38  */
  39 static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
  40 {
  41         u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12);
  42         int cpu = smp_processor_id();
  43         if (dev_base != mmcfg_last_accessed_device ||
  44             cpu != mmcfg_last_accessed_cpu) {
  45                 mmcfg_last_accessed_device = dev_base;
  46                 mmcfg_last_accessed_cpu = cpu;
  47                 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
  48         }
  49 }
  50 
  51 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
  52                           unsigned int devfn, int reg, int len, u32 *value)
  53 {
  54         unsigned long flags;
  55         u32 base;
  56 
  57         if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
  58 err:            *value = -1;
  59                 return -EINVAL;
  60         }
  61 
  62         rcu_read_lock();
  63         base = get_base_addr(seg, bus, devfn);
  64         if (!base) {
  65                 rcu_read_unlock();
  66                 goto err;
  67         }
  68 
  69         raw_spin_lock_irqsave(&pci_config_lock, flags);
  70 
  71         pci_exp_set_dev_base(base, bus, devfn);
  72 
  73         switch (len) {
  74         case 1:
  75                 *value = mmio_config_readb(mmcfg_virt_addr + reg);
  76                 break;
  77         case 2:
  78                 *value = mmio_config_readw(mmcfg_virt_addr + reg);
  79                 break;
  80         case 4:
  81                 *value = mmio_config_readl(mmcfg_virt_addr + reg);
  82                 break;
  83         }
  84         raw_spin_unlock_irqrestore(&pci_config_lock, flags);
  85         rcu_read_unlock();
  86 
  87         return 0;
  88 }
  89 
  90 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
  91                            unsigned int devfn, int reg, int len, u32 value)
  92 {
  93         unsigned long flags;
  94         u32 base;
  95 
  96         if ((bus > 255) || (devfn > 255) || (reg > 4095))
  97                 return -EINVAL;
  98 
  99         rcu_read_lock();
 100         base = get_base_addr(seg, bus, devfn);
 101         if (!base) {
 102                 rcu_read_unlock();
 103                 return -EINVAL;
 104         }
 105 
 106         raw_spin_lock_irqsave(&pci_config_lock, flags);
 107 
 108         pci_exp_set_dev_base(base, bus, devfn);
 109 
 110         switch (len) {
 111         case 1:
 112                 mmio_config_writeb(mmcfg_virt_addr + reg, value);
 113                 break;
 114         case 2:
 115                 mmio_config_writew(mmcfg_virt_addr + reg, value);
 116                 break;
 117         case 4:
 118                 mmio_config_writel(mmcfg_virt_addr + reg, value);
 119                 break;
 120         }
 121         raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 122         rcu_read_unlock();
 123 
 124         return 0;
 125 }
 126 
 127 const struct pci_raw_ops pci_mmcfg = {
 128         .read =         pci_mmcfg_read,
 129         .write =        pci_mmcfg_write,
 130 };
 131 
 132 int __init pci_mmcfg_arch_init(void)
 133 {
 134         printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
 135         raw_pci_ext_ops = &pci_mmcfg;
 136         return 1;
 137 }
 138 
 139 void __init pci_mmcfg_arch_free(void)
 140 {
 141 }
 142 
 143 int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
 144 {
 145         return 0;
 146 }
 147 
 148 void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
 149 {
 150         unsigned long flags;
 151 
 152         /* Invalidate the cached mmcfg map entry. */
 153         raw_spin_lock_irqsave(&pci_config_lock, flags);
 154         mmcfg_last_accessed_device = 0;
 155         raw_spin_unlock_irqrestore(&pci_config_lock, flags);
 156 }

/* [<][>][^][v][top][bottom][index][help] */