Release 4.14 arch/x86/pci/direct.c
// SPDX-License-Identifier: GPL-2.0
/*
* direct.c - Low-level direct PCI config space access
*/
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/dmi.h>
#include <asm/pci_x86.h>
/*
* Functions for accessing PCI base (first 256 bytes) and extended
* (4096 bytes per PCI function) configuration space with type 1
* accesses.
*/
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | ((reg & 0xF00) << 16) | (bus << 16) \
| (devfn << 8) | (reg & 0xFC))
static int pci_conf1_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
*value = -1;
return -EINVAL;
}
raw_spin_lock_irqsave(&pci_config_lock, flags);
outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
switch (len) {
case 1:
*value = inb(0xCFC + (reg & 3));
break;
case 2:
*value = inw(0xCFC + (reg & 2));
break;
case 4:
*value = inl(0xCFC);
break;
}
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 131 | 85.62% | 1 | 11.11% |
Andi Kleen | 8 | 5.23% | 1 | 11.11% |
Matthew Wilcox | 6 | 3.92% | 3 | 33.33% |
Björn Helgaas | 3 | 1.96% | 1 | 11.11% |
Thomas Gleixner | 2 | 1.31% | 1 | 11.11% |
Jan Beulich | 2 | 1.31% | 1 | 11.11% |
Robert Richter | 1 | 0.65% | 1 | 11.11% |
Total | 153 | 100.00% | 9 | 100.00% |
static int pci_conf1_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
unsigned long flags;
if (seg || (bus > 255) || (devfn > 255) || (reg > 4095))
return -EINVAL;
raw_spin_lock_irqsave(&pci_config_lock, flags);
outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
switch (len) {
case 1:
outb((u8)value, 0xCFC + (reg & 3));
break;
case 2:
outw((u16)value, 0xCFC + (reg & 2));
break;
case 4:
outl((u32)value, 0xCFC);
break;
}
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 136 | 90.67% | 1 | 12.50% |
Matthew Wilcox | 6 | 4.00% | 3 | 37.50% |
Björn Helgaas | 3 | 2.00% | 1 | 12.50% |
Thomas Gleixner | 2 | 1.33% | 1 | 12.50% |
Jan Beulich | 2 | 1.33% | 1 | 12.50% |
Robert Richter | 1 | 0.67% | 1 | 12.50% |
Total | 150 | 100.00% | 8 | 100.00% |
#undef PCI_CONF1_ADDRESS
const struct pci_raw_ops pci_direct_conf1 = {
.read = pci_conf1_read,
.write = pci_conf1_write,
};
/*
* Functions for accessing PCI configuration space with type 2 accesses
*/
#define PCI_CONF2_ADDRESS(dev, reg) (u16)(0xC000 | (dev << 8) | reg)
static int pci_conf2_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
int dev, fn;
WARN_ON(seg);
if ((bus > 255) || (devfn > 255) || (reg > 255)) {
*value = -1;
return -EINVAL;
}
dev = PCI_SLOT(devfn);
fn = PCI_FUNC(devfn);
if (dev & 0x10)
return PCIBIOS_DEVICE_NOT_FOUND;
raw_spin_lock_irqsave(&pci_config_lock, flags);
outb((u8)(0xF0 | (fn << 1)), 0xCF8);
outb((u8)bus, 0xCFA);
switch (len) {
case 1:
*value = inb(PCI_CONF2_ADDRESS(dev, reg));
break;
case 2:
*value = inw(PCI_CONF2_ADDRESS(dev, reg));
break;
case 4:
*value = inl(PCI_CONF2_ADDRESS(dev, reg));
break;
}
outb(0, 0xCF8);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 167 | 80.29% | 1 | 14.29% |
Matthew Wilcox | 23 | 11.06% | 2 | 28.57% |
Andi Kleen | 8 | 3.85% | 1 | 14.29% |
Jan Beulich | 5 | 2.40% | 1 | 14.29% |
Björn Helgaas | 3 | 1.44% | 1 | 14.29% |
Thomas Gleixner | 2 | 0.96% | 1 | 14.29% |
Total | 208 | 100.00% | 7 | 100.00% |
static int pci_conf2_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
unsigned long flags;
int dev, fn;
WARN_ON(seg);
if ((bus > 255) || (devfn > 255) || (reg > 255))
return -EINVAL;
dev = PCI_SLOT(devfn);
fn = PCI_FUNC(devfn);
if (dev & 0x10)
return PCIBIOS_DEVICE_NOT_FOUND;
raw_spin_lock_irqsave(&pci_config_lock, flags);
outb((u8)(0xF0 | (fn << 1)), 0xCF8);
outb((u8)bus, 0xCFA);
switch (len) {
case 1:
outb((u8)value, PCI_CONF2_ADDRESS(dev, reg));
break;
case 2:
outw((u16)value, PCI_CONF2_ADDRESS(dev, reg));
break;
case 4:
outl((u32)value, PCI_CONF2_ADDRESS(dev, reg));
break;
}
outb(0, 0xCF8);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 137 | 66.83% | 1 | 14.29% |
Matthew Dobson | 35 | 17.07% | 1 | 14.29% |
Matthew Wilcox | 23 | 11.22% | 2 | 28.57% |
Jan Beulich | 5 | 2.44% | 1 | 14.29% |
Björn Helgaas | 3 | 1.46% | 1 | 14.29% |
Thomas Gleixner | 2 | 0.98% | 1 | 14.29% |
Total | 205 | 100.00% | 7 | 100.00% |
#undef PCI_CONF2_ADDRESS
static const struct pci_raw_ops pci_direct_conf2 = {
.read = pci_conf2_read,
.write = pci_conf2_write,
};
/*
* Before we decide to use direct hardware access mechanisms, we try to do some
* trivial checks to ensure it at least _seems_ to be working -- we just test
* whether bus 00 contains a host bridge (this is similar to checking
* techniques used in XFree86, but ours should be more reliable since we
* attempt to make use of direct access hints provided by the PCI BIOS).
*
* This should be close to trivial, but it isn't, because there are buggy
* chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
*/
static int __init pci_sanity_check(const struct pci_raw_ops *o)
{
u32 x = 0;
int year, devfn;
if (pci_probe & PCI_NO_CHECKS)
return 1;
/* Assume Type 1 works for newer systems.
This handles machines that don't have anything on PCI Bus 0. */
dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL);
if (year >= 2001)
return 1;
for (devfn = 0; devfn < 0x100; devfn++) {
if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x))
continue;
if (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)
return 1;
if (o->read(0, 0, devfn, PCI_VENDOR_ID, 2, &x))
continue;
if (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)
return 1;
}
DBG(KERN_WARNING "PCI: Sanity check failed\n");
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 78 | 53.42% | 1 | 10.00% |
Matthew Wilcox | 28 | 19.18% | 2 | 20.00% |
Tejun Heo | 14 | 9.59% | 1 | 10.00% |
Andi Kleen | 10 | 6.85% | 1 | 10.00% |
Matthew Dobson | 9 | 6.16% | 1 | 10.00% |
Greg Kroah-Hartman | 5 | 3.42% | 2 | 20.00% |
Jan Beulich | 1 | 0.68% | 1 | 10.00% |
Daniel Marjamäki | 1 | 0.68% | 1 | 10.00% |
Total | 146 | 100.00% | 10 | 100.00% |
static int __init pci_check_type1(void)
{
unsigned long flags;
unsigned int tmp;
int works = 0;
local_irq_save(flags);
outb(0x01, 0xCFB);
tmp = inl(0xCF8);
outl(0x80000000, 0xCF8);
if (inl(0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) {
works = 1;
}
outl(tmp, 0xCF8);
local_irq_restore(flags);
return works;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 64 | 76.19% | 1 | 20.00% |
Matthew Wilcox | 15 | 17.86% | 1 | 20.00% |
Matthew Dobson | 3 | 3.57% | 1 | 20.00% |
Ingo Molnar | 2 | 2.38% | 2 | 40.00% |
Total | 84 | 100.00% | 5 | 100.00% |
static int __init pci_check_type2(void)
{
unsigned long flags;
int works = 0;
local_irq_save(flags);
outb(0x00, 0xCFB);
outb(0x00, 0xCF8);
outb(0x00, 0xCFA);
if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00 &&
pci_sanity_check(&pci_direct_conf2)) {
works = 1;
}
local_irq_restore(flags);
return works;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 51 | 63.75% | 1 | 33.33% |
Matthew Wilcox | 28 | 35.00% | 1 | 33.33% |
Ingo Molnar | 1 | 1.25% | 1 | 33.33% |
Total | 80 | 100.00% | 3 | 100.00% |
void __init pci_direct_init(int type)
{
if (type == 0)
return;
printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
type);
if (type == 1) {
raw_pci_ops = &pci_direct_conf1;
if (raw_pci_ext_ops)
return;
if (!(pci_probe & PCI_HAS_IO_ECS))
return;
printk(KERN_INFO "PCI: Using configuration type 1 "
"for extended access\n");
raw_pci_ext_ops = &pci_direct_conf1;
return;
}
raw_pci_ops = &pci_direct_conf2;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Andi Kleen | 36 | 51.43% | 3 | 42.86% |
Robert Richter | 30 | 42.86% | 2 | 28.57% |
Matthew Wilcox | 3 | 4.29% | 1 | 14.29% |
Yinghai Lu | 1 | 1.43% | 1 | 14.29% |
Total | 70 | 100.00% | 7 | 100.00% |
int __init pci_direct_probe(void)
{
if ((pci_probe & PCI_PROBE_CONF1) == 0)
goto type2;
if (!request_region(0xCF8, 8, "PCI conf1"))
goto type2;
if (pci_check_type1()) {
raw_pci_ops = &pci_direct_conf1;
port_cf9_safe = true;
return 1;
}
release_region(0xCF8, 8);
type2:
if ((pci_probe & PCI_PROBE_CONF2) == 0)
return 0;
if (!request_region(0xCF8, 4, "PCI conf2"))
return 0;
if (!request_region(0xC000, 0x1000, "PCI conf2"))
goto fail2;
if (pci_check_type2()) {
raw_pci_ops = &pci_direct_conf2;
port_cf9_safe = true;
return 2;
}
release_region(0xC000, 0x1000);
fail2:
release_region(0xCF8, 4);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Matthew Wilcox | 68 | 46.90% | 2 | 22.22% |
Julia Lawall | 21 | 14.48% | 1 | 11.11% |
Andi Kleen | 19 | 13.10% | 1 | 11.11% |
Patrick Mochel | 17 | 11.72% | 1 | 11.11% |
H. Peter Anvin | 8 | 5.52% | 1 | 11.11% |
Yinghai Lu | 7 | 4.83% | 1 | 11.11% |
Greg Kroah-Hartman | 3 | 2.07% | 1 | 11.11% |
Matthew Dobson | 2 | 1.38% | 1 | 11.11% |
Total | 145 | 100.00% | 9 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 823 | 62.35% | 1 | 3.12% |
Matthew Wilcox | 203 | 15.38% | 5 | 15.62% |
Andi Kleen | 84 | 6.36% | 6 | 18.75% |
Matthew Dobson | 70 | 5.30% | 1 | 3.12% |
Robert Richter | 34 | 2.58% | 2 | 6.25% |
Julia Lawall | 21 | 1.59% | 1 | 3.12% |
Jan Beulich | 18 | 1.36% | 2 | 6.25% |
Tejun Heo | 14 | 1.06% | 1 | 3.12% |
Björn Helgaas | 12 | 0.91% | 1 | 3.12% |
Greg Kroah-Hartman | 9 | 0.68% | 4 | 12.50% |
H. Peter Anvin | 8 | 0.61% | 1 | 3.12% |
Thomas Gleixner | 8 | 0.61% | 1 | 3.12% |
Yinghai Lu | 8 | 0.61% | 1 | 3.12% |
Ingo Molnar | 3 | 0.23% | 2 | 6.25% |
Tom Rini | 3 | 0.23% | 1 | 3.12% |
Daniel Marjamäki | 1 | 0.08% | 1 | 3.12% |
Jaswinder Singh Rajput | 1 | 0.08% | 1 | 3.12% |
Total | 1320 | 100.00% | 32 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.