Commit 8c073517 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 PCI updates from Thomas Gleixner:
 "This update provides the seperation of x86 PCI accessors from the
  global PCI lock in the generic PCI config space accessors.

  The reasons for this are:

   - x86 has it's own PCI config lock for various reasons, so the
     accessors have to lock two locks nested.

   - The ECAM (mmconfig) access to the extended configuration space does
     not require locking. The existing generic locking causes a massive
     lock contention when accessing the extended config space of the
     Uncore facility for performance monitoring.

  The commit which switched the access to the primary config space over
  to ECAM mode has been removed from the branch, so the primary config
  space is still accessed with type1 accessors properly serialized by
  the x86 internal locking.

  Bjorn agreed on merging this through the x86 tree"

* 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/PCI: Select CONFIG_PCI_LOCKLESS_CONFIG
  PCI: Provide Kconfig option for lockless config space accessors
  x86/PCI/ce4100: Properly lock accessor functions
  x86/PCI: Abort if legacy init fails
  x86/PCI: Remove duplicate defines
parents 03ffbcdd df65c1bc
...@@ -168,6 +168,7 @@ config X86 ...@@ -168,6 +168,7 @@ config X86
select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_USER_RETURN_NOTIFIER select HAVE_USER_RETURN_NOTIFIER
select IRQ_FORCED_THREADING select IRQ_FORCED_THREADING
select PCI_LOCKLESS_CONFIG
select PERF_EVENTS select PERF_EVENTS
select RTC_LIB select RTC_LIB
select RTC_MC146818_LIB select RTC_MC146818_LIB
......
...@@ -77,14 +77,8 @@ static inline bool is_vmd(struct pci_bus *bus) ...@@ -77,14 +77,8 @@ static inline bool is_vmd(struct pci_bus *bus)
extern unsigned int pcibios_assign_all_busses(void); extern unsigned int pcibios_assign_all_busses(void);
extern int pci_legacy_init(void); extern int pci_legacy_init(void);
# ifdef CONFIG_ACPI
# define x86_default_pci_init pci_acpi_init
# else
# define x86_default_pci_init pci_legacy_init
# endif
#else #else
# define pcibios_assign_all_busses() 0 static inline int pcibios_assign_all_busses(void) { return 0; }
# define x86_default_pci_init NULL
#endif #endif
extern unsigned long pci_mem_start; extern unsigned long pci_mem_start;
......
...@@ -65,6 +65,9 @@ struct sim_reg_op { ...@@ -65,6 +65,9 @@ struct sim_reg_op {
{ PCI_DEVFN(device, func), offset, init_op, read_op, write_op,\ { PCI_DEVFN(device, func), offset, init_op, read_op, write_op,\
{0, SIZE_TO_MASK(size)} }, {0, SIZE_TO_MASK(size)} },
/*
* All read/write functions are called with pci_config_lock held.
*/
static void reg_init(struct sim_dev_reg *reg) static void reg_init(struct sim_dev_reg *reg)
{ {
pci_direct_conf1.read(0, 1, reg->dev_func, reg->reg, 4, pci_direct_conf1.read(0, 1, reg->dev_func, reg->reg, 4,
...@@ -73,21 +76,13 @@ static void reg_init(struct sim_dev_reg *reg) ...@@ -73,21 +76,13 @@ static void reg_init(struct sim_dev_reg *reg)
static void reg_read(struct sim_dev_reg *reg, u32 *value) static void reg_read(struct sim_dev_reg *reg, u32 *value)
{ {
unsigned long flags;
raw_spin_lock_irqsave(&pci_config_lock, flags);
*value = reg->sim_reg.value; *value = reg->sim_reg.value;
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
} }
static void reg_write(struct sim_dev_reg *reg, u32 value) static void reg_write(struct sim_dev_reg *reg, u32 value)
{ {
unsigned long flags;
raw_spin_lock_irqsave(&pci_config_lock, flags);
reg->sim_reg.value = (value & reg->sim_reg.mask) | reg->sim_reg.value = (value & reg->sim_reg.mask) |
(reg->sim_reg.value & ~reg->sim_reg.mask); (reg->sim_reg.value & ~reg->sim_reg.mask);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
} }
static void sata_reg_init(struct sim_dev_reg *reg) static void sata_reg_init(struct sim_dev_reg *reg)
...@@ -117,12 +112,8 @@ static void sata_revid_read(struct sim_dev_reg *reg, u32 *value) ...@@ -117,12 +112,8 @@ static void sata_revid_read(struct sim_dev_reg *reg, u32 *value)
static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value) static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value)
{ {
unsigned long flags;
raw_spin_lock_irqsave(&pci_config_lock, flags);
/* force interrupt pin value to 0 */ /* force interrupt pin value to 0 */
*value = reg->sim_reg.value & 0xfff00ff; *value = reg->sim_reg.value & 0xfff00ff;
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
} }
static struct sim_dev_reg bus1_fixups[] = { static struct sim_dev_reg bus1_fixups[] = {
...@@ -265,24 +256,33 @@ int bridge_read(unsigned int devfn, int reg, int len, u32 *value) ...@@ -265,24 +256,33 @@ int bridge_read(unsigned int devfn, int reg, int len, u32 *value)
return retval; return retval;
} }
static int ce4100_conf_read(unsigned int seg, unsigned int bus, static int ce4100_bus1_read(unsigned int devfn, int reg, int len, u32 *value)
unsigned int devfn, int reg, int len, u32 *value)
{ {
unsigned long flags;
int i; int i;
WARN_ON(seg); for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus == 1) { if (bus1_fixups[i].dev_func == devfn &&
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { bus1_fixups[i].reg == (reg & ~3) &&
if (bus1_fixups[i].dev_func == devfn && bus1_fixups[i].read) {
bus1_fixups[i].reg == (reg & ~3) &&
bus1_fixups[i].read) { raw_spin_lock_irqsave(&pci_config_lock, flags);
bus1_fixups[i].read(&(bus1_fixups[i]), bus1_fixups[i].read(&(bus1_fixups[i]), value);
value); raw_spin_unlock_irqrestore(&pci_config_lock, flags);
extract_bytes(value, reg, len); extract_bytes(value, reg, len);
return 0; return 0;
}
} }
} }
return -1;
}
static int ce4100_conf_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
WARN_ON(seg);
if (bus == 1 && !ce4100_bus1_read(devfn, reg, len, value))
return 0;
if (bus == 0 && (PCI_DEVFN(1, 0) == devfn) && if (bus == 0 && (PCI_DEVFN(1, 0) == devfn) &&
!bridge_read(devfn, reg, len, value)) !bridge_read(devfn, reg, len, value))
...@@ -291,23 +291,32 @@ static int ce4100_conf_read(unsigned int seg, unsigned int bus, ...@@ -291,23 +291,32 @@ static int ce4100_conf_read(unsigned int seg, unsigned int bus,
return pci_direct_conf1.read(seg, bus, devfn, reg, len, value); return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
} }
static int ce4100_conf_write(unsigned int seg, unsigned int bus, static int ce4100_bus1_write(unsigned int devfn, int reg, int len, u32 value)
unsigned int devfn, int reg, int len, u32 value)
{ {
unsigned long flags;
int i; int i;
WARN_ON(seg); for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus == 1) { if (bus1_fixups[i].dev_func == devfn &&
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) { bus1_fixups[i].reg == (reg & ~3) &&
if (bus1_fixups[i].dev_func == devfn && bus1_fixups[i].write) {
bus1_fixups[i].reg == (reg & ~3) &&
bus1_fixups[i].write) { raw_spin_lock_irqsave(&pci_config_lock, flags);
bus1_fixups[i].write(&(bus1_fixups[i]), bus1_fixups[i].write(&(bus1_fixups[i]), value);
value); raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return 0; return 0;
}
} }
} }
return -1;
}
static int ce4100_conf_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
WARN_ON(seg);
if (bus == 1 && !ce4100_bus1_write(devfn, reg, len, value))
return 0;
/* Discard writes to A/V bridge BAR. */ /* Discard writes to A/V bridge BAR. */
if (bus == 0 && PCI_DEVFN(1, 0) == devfn && if (bus == 0 && PCI_DEVFN(1, 0) == devfn &&
...@@ -318,8 +327,8 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus, ...@@ -318,8 +327,8 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus,
} }
static const struct pci_raw_ops ce4100_pci_conf = { static const struct pci_raw_ops ce4100_pci_conf = {
.read = ce4100_conf_read, .read = ce4100_conf_read,
.write = ce4100_conf_write, .write = ce4100_conf_write,
}; };
int __init ce4100_pci_init(void) int __init ce4100_pci_init(void)
......
...@@ -75,8 +75,8 @@ struct pci_ops pci_root_ops = { ...@@ -75,8 +75,8 @@ struct pci_ops pci_root_ops = {
}; };
/* /*
* This interrupt-safe spinlock protects all accesses to PCI * This interrupt-safe spinlock protects all accesses to PCI configuration
* configuration space. * space, except for the mmconfig (ECAM) based operations.
*/ */
DEFINE_RAW_SPINLOCK(pci_config_lock); DEFINE_RAW_SPINLOCK(pci_config_lock);
......
...@@ -24,12 +24,10 @@ static void pcibios_fixup_peer_bridges(void) ...@@ -24,12 +24,10 @@ static void pcibios_fixup_peer_bridges(void)
int __init pci_legacy_init(void) int __init pci_legacy_init(void)
{ {
if (!raw_pci_ops) { if (!raw_pci_ops)
printk("PCI: System does not support PCI\n"); return 1;
return 0;
}
printk("PCI: Probing PCI hardware\n"); pr_info("PCI: Probing PCI hardware\n");
pcibios_scan_root(0); pcibios_scan_root(0);
return 0; return 0;
} }
...@@ -46,7 +44,7 @@ void pcibios_scan_specific_bus(int busn) ...@@ -46,7 +44,7 @@ void pcibios_scan_specific_bus(int busn)
if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) && if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
l != 0x0000 && l != 0xffff) { l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l); DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn); pr_info("PCI: Discovered peer bus %02x\n", busn);
pcibios_scan_root(busn); pcibios_scan_root(busn);
return; return;
} }
...@@ -60,8 +58,12 @@ static int __init pci_subsys_init(void) ...@@ -60,8 +58,12 @@ static int __init pci_subsys_init(void)
* The init function returns an non zero value when * The init function returns an non zero value when
* pci_legacy_init should be invoked. * pci_legacy_init should be invoked.
*/ */
if (x86_init.pci.init()) if (x86_init.pci.init()) {
pci_legacy_init(); if (pci_legacy_init()) {
pr_info("PCI: System does not support PCI\n");
return -ENODEV;
}
}
pcibios_fixup_peer_bridges(); pcibios_fixup_peer_bridges();
x86_init.pci.init_irq(); x86_init.pci.init_irq();
......
...@@ -86,6 +86,9 @@ config PCI_ATS ...@@ -86,6 +86,9 @@ config PCI_ATS
config PCI_ECAM config PCI_ECAM
bool bool
config PCI_LOCKLESS_CONFIG
bool
config PCI_IOV config PCI_IOV
bool "PCI IOV support" bool "PCI IOV support"
depends on PCI depends on PCI
......
...@@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock); ...@@ -25,6 +25,14 @@ DEFINE_RAW_SPINLOCK(pci_lock);
#define PCI_word_BAD (pos & 1) #define PCI_word_BAD (pos & 1)
#define PCI_dword_BAD (pos & 3) #define PCI_dword_BAD (pos & 3)
#ifdef CONFIG_PCI_LOCKLESS_CONFIG
# define pci_lock_config(f) do { (void)(f); } while (0)
# define pci_unlock_config(f) do { (void)(f); } while (0)
#else
# define pci_lock_config(f) raw_spin_lock_irqsave(&pci_lock, f)
# define pci_unlock_config(f) raw_spin_unlock_irqrestore(&pci_lock, f)
#endif
#define PCI_OP_READ(size, type, len) \ #define PCI_OP_READ(size, type, len) \
int pci_bus_read_config_##size \ int pci_bus_read_config_##size \
(struct pci_bus *bus, unsigned int devfn, int pos, type *value) \ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
...@@ -33,10 +41,10 @@ int pci_bus_read_config_##size \ ...@@ -33,10 +41,10 @@ int pci_bus_read_config_##size \
unsigned long flags; \ unsigned long flags; \
u32 data = 0; \ u32 data = 0; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
raw_spin_lock_irqsave(&pci_lock, flags); \ pci_lock_config(flags); \
res = bus->ops->read(bus, devfn, pos, len, &data); \ res = bus->ops->read(bus, devfn, pos, len, &data); \
*value = (type)data; \ *value = (type)data; \
raw_spin_unlock_irqrestore(&pci_lock, flags); \ pci_unlock_config(flags); \
return res; \ return res; \
} }
...@@ -47,9 +55,9 @@ int pci_bus_write_config_##size \ ...@@ -47,9 +55,9 @@ int pci_bus_write_config_##size \
int res; \ int res; \
unsigned long flags; \ unsigned long flags; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
raw_spin_lock_irqsave(&pci_lock, flags); \ pci_lock_config(flags); \
res = bus->ops->write(bus, devfn, pos, len, value); \ res = bus->ops->write(bus, devfn, pos, len, value); \
raw_spin_unlock_irqrestore(&pci_lock, flags); \ pci_unlock_config(flags); \
return res; \ return res; \
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment