Skip to content

Commit

Permalink
x86/PCI/ce4100: Properly lock accessor functions
Browse files Browse the repository at this point in the history
x86 wants to get rid of the global pci_lock protecting the config space
accessors so ECAM mode can operate completely lockless, but the CE4100 PCI
code relies on that to protect the simulation registers.

Restructure the code so it uses the x86 specific pci_config_lock to
serialize the inner workings of the CE4100 PCI magic. That allows to remove
the global locking via pci_lock later.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Bjorn Helgaas <helgaas@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: linux-pci@vger.kernel.org
Link: http://lkml.kernel.org/r/20170316215057.126873574@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Jun 28, 2017
1 parent aae3e31 commit bb290fd
Showing 1 changed file with 48 additions and 39 deletions.
87 changes: 48 additions & 39 deletions arch/x86/pci/ce4100.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct sim_reg_op {
{ PCI_DEVFN(device, func), offset, init_op, read_op, write_op,\
{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)
{
pci_direct_conf1.read(0, 1, reg->dev_func, reg->reg, 4,
Expand All @@ -73,21 +76,13 @@ static void reg_init(struct sim_dev_reg *reg)

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;
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
}

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 & ~reg->sim_reg.mask);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
}

static void sata_reg_init(struct sim_dev_reg *reg)
Expand Down Expand Up @@ -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)
{
unsigned long flags;

raw_spin_lock_irqsave(&pci_config_lock, flags);
/* force interrupt pin value to 0 */
*value = reg->sim_reg.value & 0xfff00ff;
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
}

static struct sim_dev_reg bus1_fixups[] = {
Expand Down Expand Up @@ -265,24 +256,33 @@ int bridge_read(unsigned int devfn, int reg, int len, u32 *value)
return retval;
}

static int ce4100_conf_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
static int ce4100_bus1_read(unsigned int devfn, int reg, int len, u32 *value)
{
unsigned long flags;
int i;

WARN_ON(seg);
if (bus == 1) {
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus1_fixups[i].dev_func == devfn &&
bus1_fixups[i].reg == (reg & ~3) &&
bus1_fixups[i].read) {
bus1_fixups[i].read(&(bus1_fixups[i]),
value);
extract_bytes(value, reg, len);
return 0;
}
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus1_fixups[i].dev_func == devfn &&
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]), value);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
extract_bytes(value, reg, len);
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) &&
!bridge_read(devfn, reg, len, value))
Expand All @@ -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);
}

static int ce4100_conf_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
static int ce4100_bus1_write(unsigned int devfn, int reg, int len, u32 value)
{
unsigned long flags;
int i;

WARN_ON(seg);
if (bus == 1) {
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus1_fixups[i].dev_func == devfn &&
bus1_fixups[i].reg == (reg & ~3) &&
bus1_fixups[i].write) {
bus1_fixups[i].write(&(bus1_fixups[i]),
value);
return 0;
}
for (i = 0; i < ARRAY_SIZE(bus1_fixups); i++) {
if (bus1_fixups[i].dev_func == devfn &&
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]), value);
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
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. */
if (bus == 0 && PCI_DEVFN(1, 0) == devfn &&
Expand All @@ -318,8 +327,8 @@ static int ce4100_conf_write(unsigned int seg, unsigned int bus,
}

static const struct pci_raw_ops ce4100_pci_conf = {
.read = ce4100_conf_read,
.write = ce4100_conf_write,
.read = ce4100_conf_read,
.write = ce4100_conf_write,
};

int __init ce4100_pci_init(void)
Expand Down

0 comments on commit bb290fd

Please sign in to comment.