linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu
@ 2012-11-13  9:07 Takao Indoh
  2012-11-13  9:07 ` [PATCH v6 1/5] x86, pci: add dummy pci device for early stage Takao Indoh
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:07 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: andi, tokunaga.keiich, kexec, hbabu, mingo, ddutile, vgoyal,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, Takao Indoh,
	khalid

These patches reset PCIe devices at boot time to address DMA problem on
kdump with iommu. When "reset_devices" is specified, a hot reset is
triggered on each PCIe root port and downstream port to reset its
downstream endpoint.

Background:
A kdump problem about DMA has been discussed for a long time. That is,
when a kernel is switched to the kdump kernel, DMA derived from first
kernel affects second kernel. Especially this problem surfaces when
iommu is used for PCI passthrough on KVM guest. In the case of the
machine I use, when intel_iommu=on is specified, DMAR error is detected
in kdump kernel and PCI SERR is also detected. Finally kdump fails
because some devices does not work correctly.

The root cause is that ongoing DMA from first kernel causes DMAR fault
because page table of DMAR is initialized while kdump kernel is booting
up. Therefore to solve this problem DMA needs to be stopped before DMAR
is initialized at kdump kernel boot time. By these patches, PCIe devices
are reset by hot reset and its DMA is stopped when reset_devices is
specified. One problem of this solution is that the monitor blacks out
when VGA controller is reset. So this patch does not reset the port
whose child endpoint is VGA device.

What I tried:
- Clearing bus master bit and INTx disable bit at boot time
    This did not solve this problem. I still got DMAR error on devices.
- Resetting devices in fixup_final(v1 patch)
    DMAR error disappeared, but sometimes PCI SERR was detected. This
    is well explained here.
    https://lkml.org/lkml/2012/9/9/245
    This PCI SERR seems to be related to interrupt remapping.
- Clearing bus master in setup_arch() and resetting devices in
  fixup_final
    Neither DMAR error nor PCI SERR occurred. But on certain machine
    kdump kernel hung up when resetting devices. It seems to be a
    problem specific to the platform.
- Resetting devices in setup_arch() (v2 and later patch)
    This solution solves all problems I found so far.

Changelog:
v6:
Rewrite using Yinghai's dummy-pci patch

v5:
Do bus reset after all devices are scanned and its config registers are
saved. This fixes a bug that config register is accessed without delay
after reset.
https://lkml.org/lkml/2012/10/17/47

v4:
Reduce waiting time after resetting devices. A previous patch does reset
like this:
  for (each device) {
    save config registers
    reset
    wait for 500 ms
    restore config registers
  }

If there are N devices to be reset, it takes N*500 ms. On the other
hand, the v4 patch does:
  for (each device) {
    save config registers
    reset
  }
  wait 500 ms
  for (each device) {
    restore config registers
  }
Though it needs more memory space to save config registers, the waiting
time is always 500ms.
https://lkml.org/lkml/2012/10/15/49

v3:
Move alloc_bootmem and free_bootmem to early_reset_pcie_devices so that
they are called only once.
https://lkml.org/lkml/2012/10/10/57

v2:
Reset devices in setup_arch() because reset need to be done before
interrupt remapping is initialized.
https://lkml.org/lkml/2012/10/2/54

v1:
Add fixup_final quirk to reset PCIe devices
https://lkml.org/lkml/2012/8/3/160


Takao Indoh (4):
  PCI: Define the maximum number of PCI function
  Make reset_devices available at early stage
  x86, pci: Reset PCIe devices at boot time
  x86, pci: Enable PCI INTx when MSI is disabled

Yinghai Lu (1):
  x86, pci: add dummy pci device for early stage

 arch/x86/include/asm/pci-direct.h |    3 +
 arch/x86/kernel/setup.c           |    3 +
 arch/x86/pci/common.c             |    4 +-
 arch/x86/pci/early.c              |  303 +++++++++++++++++++++++++++++++++++++
 include/linux/pci.h               |    2 +
 init/main.c                       |    4 +-
 6 files changed, 316 insertions(+), 3 deletions(-)



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v6 1/5] x86, pci: add dummy pci device for early stage
  2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
@ 2012-11-13  9:07 ` Takao Indoh
  2012-11-13 10:01   ` Andrew Murray
  2012-11-13  9:07 ` [PATCH v6 2/5] PCI: Define the maximum number of PCI function Takao Indoh
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:07 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: tokunaga.keiich, kexec, hbabu, andi, ddutile, Takao Indoh,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, mingo, vgoyal,
	khalid

From: Yinghai Lu <yinghai@kernel.org>

So we can pass pci_dev *dev to reuse some generic pci functions.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
---
 arch/x86/include/asm/pci-direct.h |    2 +
 arch/x86/pci/early.c              |   75 +++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/pci-direct.h b/arch/x86/include/asm/pci-direct.h
index b1e7a45..b6360d3 100644
--- a/arch/x86/include/asm/pci-direct.h
+++ b/arch/x86/include/asm/pci-direct.h
@@ -18,4 +18,6 @@ extern int early_pci_allowed(void);
 extern unsigned int pci_early_dump_regs;
 extern void early_dump_pci_device(u8 bus, u8 slot, u8 func);
 extern void early_dump_pci_devices(void);
+
+struct pci_dev *get_early_pci_dev(int num, int slot, int func);
 #endif /* _ASM_X86_PCI_DIRECT_H */
diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c
index d1067d5..aea6b2b 100644
--- a/arch/x86/pci/early.c
+++ b/arch/x86/pci/early.c
@@ -109,3 +109,78 @@ void early_dump_pci_devices(void)
 		}
 	}
 }
+
+static __init int
+early_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
+			int size, u32 *value)
+{
+	int num, slot, func;
+
+	num = bus->number;
+	slot = devfn >> 3;
+	func = devfn & 7;
+	switch (size) {
+	case 1:
+		*value = read_pci_config_byte(num, slot, func, where);
+		break;
+	case 2:
+		*value = read_pci_config_16(num, slot, func, where);
+		break;
+	case 4:
+		*value = read_pci_config(num, slot, func, where);
+		break;
+	}
+
+	return 0;
+}
+
+static __init int
+early_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
+			int size, u32 value)
+{
+	int num, slot, func;
+
+	num = bus->number;
+	slot = devfn >> 3;
+	func = devfn & 7;
+	switch (size) {
+	case 1:
+		write_pci_config_byte(num, slot, func, where, (u8)value);
+		break;
+	case 2:
+		write_pci_config_16(num, slot, func, where, (u16)value);
+		break;
+	case 4:
+		write_pci_config(num, slot, func, where, (u32)value);
+		break;
+	}
+
+	return 0;
+}
+
+static __initdata struct pci_ops pci_early_ops = {
+	.read  = early_pci_read,
+	.write = early_pci_write,
+};
+static __initdata struct pci_bus pci_early_bus = {
+	.ops = &pci_early_ops,
+};
+static __initdata char pci_early_init_name[8];
+static __initdata struct pci_dev pci_early_dev = {
+	.bus = &pci_early_bus,
+	.dev = {
+		.init_name = pci_early_init_name,
+	},
+};
+
+__init struct pci_dev *get_early_pci_dev(int num, int slot, int func)
+{
+	struct pci_dev *pdev;
+
+	pdev = &pci_early_dev;
+	pdev->devfn = (slot<<3) | (func & 7);
+	pdev->bus->number = num;
+	sprintf((char *)pdev->dev.init_name, "%02x:%02x.%01x", num, slot, func);
+
+	return pdev;
+}
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 2/5] PCI: Define the maximum number of PCI function
  2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
  2012-11-13  9:07 ` [PATCH v6 1/5] x86, pci: add dummy pci device for early stage Takao Indoh
@ 2012-11-13  9:07 ` Takao Indoh
  2012-11-13  9:07 ` [PATCH v6 3/5] Make reset_devices available at early stage Takao Indoh
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:07 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: tokunaga.keiich, kexec, hbabu, andi, ddutile, vgoyal,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, mingo, Takao Indoh,
	khalid

Define the maximum number of PCI function so that PCI functions can be
enumerated without using "8".

Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
---
 include/linux/pci.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/include/linux/pci.h b/include/linux/pci.h
index ee21795..eca3231 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -35,6 +35,8 @@
 /* Include the ID list */
 #include <linux/pci_ids.h>
 
+#define PCI_MAX_FUNCTIONS 8
+
 /* pci_slot represents a physical slot */
 struct pci_slot {
 	struct pci_bus *bus;		/* The bus this slot is on */
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 3/5] Make reset_devices available at early stage
  2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
  2012-11-13  9:07 ` [PATCH v6 1/5] x86, pci: add dummy pci device for early stage Takao Indoh
  2012-11-13  9:07 ` [PATCH v6 2/5] PCI: Define the maximum number of PCI function Takao Indoh
@ 2012-11-13  9:07 ` Takao Indoh
  2012-11-13  9:08 ` [PATCH v6 4/5] x86, pci: Reset PCIe devices at boot time Takao Indoh
  2012-11-13  9:08 ` [PATCH v6 5/5] x86, pci: Enable PCI INTx when MSI is disabled Takao Indoh
  4 siblings, 0 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:07 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: tokunaga.keiich, kexec, hbabu, andi, ddutile, Takao Indoh,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, mingo, vgoyal,
	khalid

Change reset_devices from __setup to early_param so this parameter is
available at early stage.

Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
---
 init/main.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/init/main.c b/init/main.c
index e33e09d..f2b24cb 100644
--- a/init/main.c
+++ b/init/main.c
@@ -144,10 +144,10 @@ EXPORT_SYMBOL(reset_devices);
 static int __init set_reset_devices(char *str)
 {
 	reset_devices = 1;
-	return 1;
+	return 0;
 }
 
-__setup("reset_devices", set_reset_devices);
+early_param("reset_devices", set_reset_devices);
 
 static const char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 const char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 4/5] x86, pci: Reset PCIe devices at boot time
  2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
                   ` (2 preceding siblings ...)
  2012-11-13  9:07 ` [PATCH v6 3/5] Make reset_devices available at early stage Takao Indoh
@ 2012-11-13  9:08 ` Takao Indoh
  2012-11-13  9:08 ` [PATCH v6 5/5] x86, pci: Enable PCI INTx when MSI is disabled Takao Indoh
  4 siblings, 0 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:08 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: tokunaga.keiich, kexec, hbabu, andi, ddutile, vgoyal,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, mingo, Takao Indoh,
	khalid

This patch resets PCIe devices at boot time by hot reset when
"reset_devices" is specified.

Kdump with intel_iommu=on fails becasue ongoing DMA from first kernel
causes DMAR fault when page table of DMAR is initialized while kdump
kernel is booting up. To solve this problem, this patch resets PCIe
devices by hot reset and its DMA is stopped when reset_devices is
specified.

Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
---
 arch/x86/include/asm/pci-direct.h |    1 +
 arch/x86/kernel/setup.c           |    3 +
 arch/x86/pci/early.c              |  228 +++++++++++++++++++++++++++++++++++++
 3 files changed, 232 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/pci-direct.h b/arch/x86/include/asm/pci-direct.h
index b6360d3..5620070 100644
--- a/arch/x86/include/asm/pci-direct.h
+++ b/arch/x86/include/asm/pci-direct.h
@@ -18,6 +18,7 @@ extern int early_pci_allowed(void);
 extern unsigned int pci_early_dump_regs;
 extern void early_dump_pci_device(u8 bus, u8 slot, u8 func);
 extern void early_dump_pci_devices(void);
+extern void early_reset_pcie_devices(void);
 
 struct pci_dev *get_early_pci_dev(int num, int slot, int func);
 #endif /* _ASM_X86_PCI_DIRECT_H */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index ca45696..2e7928e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1001,6 +1001,9 @@ void __init setup_arch(char **cmdline_p)
 	generic_apic_probe();
 
 	early_quirks();
+#ifdef CONFIG_PCI
+	early_reset_pcie_devices();
+#endif
 
 	/*
 	 * Read APIC and some other early information from ACPI tables.
diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c
index aea6b2b..32b02c6 100644
--- a/arch/x86/pci/early.c
+++ b/arch/x86/pci/early.c
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/bootmem.h>
 #include <asm/pci-direct.h>
 #include <asm/io.h>
 #include <asm/pci_x86.h>
@@ -184,3 +185,230 @@ __init struct pci_dev *get_early_pci_dev(int num, int slot, int func)
 
 	return pdev;
 }
+
+struct save_config {
+	u32 pci[16];
+	u16 pcie[7];
+	int saved;
+};
+
+struct pcie_port {
+	struct list_head dev;
+	u8 bus;
+	u8 slot;
+	u8 func;
+	u8 secondary;
+	struct save_config save[PCI_MAX_FUNCTIONS];
+};
+
+static __initdata LIST_HEAD(device_list);
+static void __init early_udelay(int loops)
+{
+	while (loops--) {
+		/* Approximately 1 us */
+		native_io_delay();
+	}
+}
+
+struct pci_dev * __init early_pci_dev_init(int bus, int slot, int func)
+{
+	u16 vendor;
+	u8 type;
+	struct pci_dev *pdev;
+
+	pdev = get_early_pci_dev(bus, slot, func);
+	pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
+	if (vendor == 0xffff)
+		return NULL;
+
+	pci_read_config_byte(pdev, PCI_HEADER_TYPE, &type);
+	pdev->hdr_type = type;
+	set_pcie_port_type(pdev);
+
+	return pdev;
+}
+
+static void __init do_reset(u8 bus, u8 slot, u8 func)
+{
+	u16 ctrl;
+	struct pci_dev *dev;
+
+	dev = get_early_pci_dev(bus, slot, func);
+	printk(KERN_INFO "pci 0000:%02x:%02x.%d reset\n", bus, slot, func);
+
+	/* Assert Secondary Bus Reset */
+	pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+	ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+
+	/*
+	 * PCIe spec requires software to ensure a minimum reset duration
+	 * (Trst == 1ms). We have here 5ms safety margin because early_udelay
+	 * is not precise.
+	 */
+	early_udelay(5000);
+
+	/* De-assert Secondary Bus Reset */
+	ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+	pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+}
+
+static void __init save_state(unsigned bus, unsigned slot, unsigned func,
+			      struct save_config *save)
+{
+	struct pci_dev *dev;
+	int i;
+
+	dev = get_early_pci_dev(bus, slot, func);
+	printk(KERN_INFO "pci 0000:%02x:%02x.%d save state\n", bus, slot, func);
+
+	for (i = 0; i < 16; i++)
+		pci_read_config_dword(dev, i * 4, save->pci + i);
+	i = 0;
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_LNKCTL, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_SLTCTL, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_RTCTL, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_DEVCTL2, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &save->pcie[i++]);
+	pcie_capability_read_word(dev, PCI_EXP_SLTCTL2, &save->pcie[i++]);
+
+	save->saved = true;
+}
+
+static void __init restore_state(unsigned bus, unsigned slot, unsigned func,
+				 struct save_config *save)
+{
+	struct pci_dev *dev;
+	int i = 0;
+
+	dev = get_early_pci_dev(bus, slot, func);
+	printk(KERN_INFO "pci 0000:%02x:%02x.%d restore state\n",
+	       bus, slot, func);
+
+	pcie_capability_write_word(dev, PCI_EXP_DEVCTL, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_LNKCTL, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_SLTCTL, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_RTCTL, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_DEVCTL2, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_LNKCTL2, save->pcie[i++]);
+	pcie_capability_write_word(dev, PCI_EXP_SLTCTL2, save->pcie[i++]);
+
+	for (i = 15; i >= 0; i--)
+		pci_write_config_dword(dev, i * 4, save->pci[i]);
+}
+
+static void __init find_pcie_device(unsigned bus, unsigned slot, unsigned func)
+{
+	struct pci_dev *dev;
+	int f, pcie_type, count;
+	u8 secondary;
+	u32 class;
+	struct pcie_port *port;
+	int children[PCI_MAX_FUNCTIONS];
+
+	dev = early_pci_dev_init(bus, slot, func);
+	if (!dev || !pci_is_pcie(dev))
+		return;
+
+	pcie_type = pci_pcie_type(dev);
+	if ((pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
+	    (pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
+		return;
+
+	if ((dev->hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+		return;
+	pci_read_config_byte(dev, PCI_SECONDARY_BUS, &secondary);
+
+	memset(children, 0, sizeof(children));
+	for (count = 0, f = 0; f < PCI_MAX_FUNCTIONS; f++) {
+		dev = early_pci_dev_init(secondary, 0, f);
+		if (!dev || !pci_is_pcie(dev))
+			continue;
+
+		pcie_type = pci_pcie_type(dev);
+		if ((pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
+		    (pcie_type == PCI_EXP_TYPE_PCI_BRIDGE))
+			/* Don't reset switch, bridge */
+			return;
+
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+		if ((class >> 24) == PCI_BASE_CLASS_DISPLAY)
+			/* Don't reset VGA device */
+			return;
+
+		count++;
+		children[f] = 1;
+	}
+
+	if (!count)
+		return;
+
+	port = (struct pcie_port *)alloc_bootmem(sizeof(struct pcie_port));
+	if (port == NULL) {
+		printk(KERN_ERR "pci 0000:%02x:%02x.%d alloc_bootmem failed\n",
+		       bus, slot, func);
+		return;
+	}
+	memset(port, 0, sizeof(*port));
+	port->bus = bus;
+	port->slot = slot;
+	port->func = func;
+	port->secondary = secondary;
+	for (f = 0; f < PCI_MAX_FUNCTIONS; f++)
+		if (children[f])
+			save_state(secondary, 0, f, &port->save[f]);
+	list_add_tail(&port->dev, &device_list);
+}
+
+void __init early_reset_pcie_devices(void)
+{
+	unsigned bus, slot, func;
+	struct pcie_port *port, *tmp;
+	struct pci_dev *dev;
+
+	if (!early_pci_allowed() || !reset_devices)
+		return;
+
+	/* Find PCIe port and save config registers of its downstream devices */
+	for (bus = 0; bus < 256; bus++) {
+		for (slot = 0; slot < 32; slot++) {
+			for (func = 0; func < PCI_MAX_FUNCTIONS; func++) {
+				u8 type;
+
+				dev = early_pci_dev_init(bus, slot, func);
+				if (!dev)
+					continue;
+
+				type = dev->hdr_type;
+				find_pcie_device(bus, slot, func);
+
+				if ((func == 0) && !(type & 0x80))
+					break;
+			}
+		}
+	}
+
+	if (list_empty(&device_list))
+		return;
+
+	/* Do bus reset */
+	list_for_each_entry(port, &device_list, dev)
+		do_reset(port->bus, port->slot, port->func);
+
+	/*
+	 * According to PCIe spec, software must wait a minimum of 100 ms
+	 * before sending a configuration request. We have 500ms safety margin
+	 * here.
+	 */
+	early_udelay(500000);
+
+	/* Restore config registers and free memory */
+	list_for_each_entry_safe(port, tmp, &device_list, dev) {
+		for (func = 0; func < PCI_MAX_FUNCTIONS; func++)
+			if (port->save[func].saved)
+				restore_state(port->secondary, 0, func,
+					      &port->save[func]);
+		free_bootmem(__pa(port), sizeof(*port));
+	}
+}
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v6 5/5] x86, pci: Enable PCI INTx when MSI is disabled
  2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
                   ` (3 preceding siblings ...)
  2012-11-13  9:08 ` [PATCH v6 4/5] x86, pci: Reset PCIe devices at boot time Takao Indoh
@ 2012-11-13  9:08 ` Takao Indoh
  4 siblings, 0 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13  9:08 UTC (permalink / raw)
  To: linux-pci, x86, linux-kernel
  Cc: tokunaga.keiich, kexec, hbabu, andi, ddutile, Takao Indoh,
	ishii.hironobu, hpa, bhelgaas, tglx, yinghai, mingo, vgoyal,
	khalid

This patch enables INTx if MSI is disabled in pcibios_enable_device().
In normal case interrupt disable bit in command register is 0b on boot
time, but in case of kdump, this bit may be 1b. It causes problems of
some drivers. At leaset I confirmed mptsas driver does not work in such
a case. This patch fix this problem.

Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
---
 arch/x86/pci/common.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 720e973..2bb7ecc 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -615,8 +615,10 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 	if ((err = pci_enable_resources(dev, mask)) < 0)
 		return err;
 
-	if (!pci_dev_msi_enabled(dev))
+	if (!pci_dev_msi_enabled(dev)) {
+		pci_intx(dev, true);
 		return pcibios_enable_irq(dev);
+	}
 	return 0;
 }
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/5] x86, pci: add dummy pci device for early stage
  2012-11-13  9:07 ` [PATCH v6 1/5] x86, pci: add dummy pci device for early stage Takao Indoh
@ 2012-11-13 10:01   ` Andrew Murray
  2012-11-13 10:57     ` Takao Indoh
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Murray @ 2012-11-13 10:01 UTC (permalink / raw)
  To: Takao Indoh
  Cc: linux-pci, x86, linux-kernel, tokunaga.keiich, kexec, hbabu,
	andi, ddutile, ishii.hironobu, hpa, bhelgaas, tglx, yinghai,
	mingo, vgoyal, khalid

Hello,

Some comments inline...

On 13 November 2012 09:07, Takao Indoh <indou.takao@jp.fujitsu.com> wrote:
> From: Yinghai Lu <yinghai@kernel.org>
>
> So we can pass pci_dev *dev to reuse some generic pci functions.
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
> ---
>  arch/x86/include/asm/pci-direct.h |    2 +
>  arch/x86/pci/early.c              |   75 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 77 insertions(+), 0 deletions(-)
>
> diff --git a/arch/x86/include/asm/pci-direct.h b/arch/x86/include/asm/pci-direct.h
> index b1e7a45..b6360d3 100644
> --- a/arch/x86/include/asm/pci-direct.h
> +++ b/arch/x86/include/asm/pci-direct.h
> @@ -18,4 +18,6 @@ extern int early_pci_allowed(void);
>  extern unsigned int pci_early_dump_regs;
>  extern void early_dump_pci_device(u8 bus, u8 slot, u8 func);
>  extern void early_dump_pci_devices(void);
> +
> +struct pci_dev *get_early_pci_dev(int num, int slot, int func);
>  #endif /* _ASM_X86_PCI_DIRECT_H */
> diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c
> index d1067d5..aea6b2b 100644
> --- a/arch/x86/pci/early.c
> +++ b/arch/x86/pci/early.c
> @@ -109,3 +109,78 @@ void early_dump_pci_devices(void)
>                 }
>         }
>  }
> +
> +static __init int
> +early_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
> +                       int size, u32 *value)
> +{
> +       int num, slot, func;
> +
> +       num = bus->number;
> +       slot = devfn >> 3;
> +       func = devfn & 7;

You may want to use the PCI_SLOT and PCI_FUNC macros in
include/linux/pci.h to determine values for slot and func.

> +       switch (size) {
> +       case 1:
> +               *value = read_pci_config_byte(num, slot, func, where);
> +               break;
> +       case 2:
> +               *value = read_pci_config_16(num, slot, func, where);
> +               break;
> +       case 4:
> +               *value = read_pci_config(num, slot, func, where);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static __init int
> +early_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
> +                       int size, u32 value)
> +{
> +       int num, slot, func;
> +
> +       num = bus->number;
> +       slot = devfn >> 3;
> +       func = devfn & 7;

As above.

> +       switch (size) {
> +       case 1:
> +               write_pci_config_byte(num, slot, func, where, (u8)value);
> +               break;
> +       case 2:
> +               write_pci_config_16(num, slot, func, where, (u16)value);
> +               break;
> +       case 4:
> +               write_pci_config(num, slot, func, where, (u32)value);
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static __initdata struct pci_ops pci_early_ops = {
> +       .read  = early_pci_read,
> +       .write = early_pci_write,
> +};
> +static __initdata struct pci_bus pci_early_bus = {
> +       .ops = &pci_early_ops,
> +};
> +static __initdata char pci_early_init_name[8];
> +static __initdata struct pci_dev pci_early_dev = {
> +       .bus = &pci_early_bus,
> +       .dev = {
> +               .init_name = pci_early_init_name,
> +       },
> +};
> +
> +__init struct pci_dev *get_early_pci_dev(int num, int slot, int func)
> +{
> +       struct pci_dev *pdev;
> +
> +       pdev = &pci_early_dev;
> +       pdev->devfn = (slot<<3) | (func & 7);

You can use PCI_DEVFN here.

> +       pdev->bus->number = num;
> +       sprintf((char *)pdev->dev.init_name, "%02x:%02x.%01x", num, slot, func);
> +
> +       return pdev;
> +}
> --
> 1.7.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Andrew Murray

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v6 1/5] x86, pci: add dummy pci device for early stage
  2012-11-13 10:01   ` Andrew Murray
@ 2012-11-13 10:57     ` Takao Indoh
  0 siblings, 0 replies; 8+ messages in thread
From: Takao Indoh @ 2012-11-13 10:57 UTC (permalink / raw)
  To: amurray
  Cc: linux-pci, x86, linux-kernel, tokunaga.keiich, kexec, hbabu,
	andi, ddutile, ishii.hironobu, hpa, bhelgaas, tglx, yinghai,
	mingo, vgoyal, khalid

(2012/11/13 19:01), Andrew Murray wrote:
> Hello,
>
> Some comments inline...
>
> On 13 November 2012 09:07, Takao Indoh <indou.takao@jp.fujitsu.com> wrote:
>> From: Yinghai Lu <yinghai@kernel.org>
>>
>> So we can pass pci_dev *dev to reuse some generic pci functions.
>>
>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>> Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
>> ---
>>   arch/x86/include/asm/pci-direct.h |    2 +
>>   arch/x86/pci/early.c              |   75 +++++++++++++++++++++++++++++++++++++
>>   2 files changed, 77 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/pci-direct.h b/arch/x86/include/asm/pci-direct.h
>> index b1e7a45..b6360d3 100644
>> --- a/arch/x86/include/asm/pci-direct.h
>> +++ b/arch/x86/include/asm/pci-direct.h
>> @@ -18,4 +18,6 @@ extern int early_pci_allowed(void);
>>   extern unsigned int pci_early_dump_regs;
>>   extern void early_dump_pci_device(u8 bus, u8 slot, u8 func);
>>   extern void early_dump_pci_devices(void);
>> +
>> +struct pci_dev *get_early_pci_dev(int num, int slot, int func);
>>   #endif /* _ASM_X86_PCI_DIRECT_H */
>> diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c
>> index d1067d5..aea6b2b 100644
>> --- a/arch/x86/pci/early.c
>> +++ b/arch/x86/pci/early.c
>> @@ -109,3 +109,78 @@ void early_dump_pci_devices(void)
>>                  }
>>          }
>>   }
>> +
>> +static __init int
>> +early_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
>> +                       int size, u32 *value)
>> +{
>> +       int num, slot, func;
>> +
>> +       num = bus->number;
>> +       slot = devfn >> 3;
>> +       func = devfn & 7;
>
> You may want to use the PCI_SLOT and PCI_FUNC macros in
> include/linux/pci.h to determine values for slot and func.
>
>> +       switch (size) {
>> +       case 1:
>> +               *value = read_pci_config_byte(num, slot, func, where);
>> +               break;
>> +       case 2:
>> +               *value = read_pci_config_16(num, slot, func, where);
>> +               break;
>> +       case 4:
>> +               *value = read_pci_config(num, slot, func, where);
>> +               break;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static __init int
>> +early_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
>> +                       int size, u32 value)
>> +{
>> +       int num, slot, func;
>> +
>> +       num = bus->number;
>> +       slot = devfn >> 3;
>> +       func = devfn & 7;
>
> As above.
>
>> +       switch (size) {
>> +       case 1:
>> +               write_pci_config_byte(num, slot, func, where, (u8)value);
>> +               break;
>> +       case 2:
>> +               write_pci_config_16(num, slot, func, where, (u16)value);
>> +               break;
>> +       case 4:
>> +               write_pci_config(num, slot, func, where, (u32)value);
>> +               break;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static __initdata struct pci_ops pci_early_ops = {
>> +       .read  = early_pci_read,
>> +       .write = early_pci_write,
>> +};
>> +static __initdata struct pci_bus pci_early_bus = {
>> +       .ops = &pci_early_ops,
>> +};
>> +static __initdata char pci_early_init_name[8];
>> +static __initdata struct pci_dev pci_early_dev = {
>> +       .bus = &pci_early_bus,
>> +       .dev = {
>> +               .init_name = pci_early_init_name,
>> +       },
>> +};
>> +
>> +__init struct pci_dev *get_early_pci_dev(int num, int slot, int func)
>> +{
>> +       struct pci_dev *pdev;
>> +
>> +       pdev = &pci_early_dev;
>> +       pdev->devfn = (slot<<3) | (func & 7);
>
> You can use PCI_DEVFN here.

Yeah, I forgot to use these macros. I'll fix them, thanks!

Thanks,
Takao Indoh

>
>> +       pdev->bus->number = num;
>> +       sprintf((char *)pdev->dev.init_name, "%02x:%02x.%01x", num, slot, func);
>> +
>> +       return pdev;
>> +}
>> --
>> 1.7.1
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
> Andrew Murray
>
>


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-11-13 11:03 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-13  9:07 [PATCH v6 0/5] Reset PCIe devices to address DMA problem on kdump with iommu Takao Indoh
2012-11-13  9:07 ` [PATCH v6 1/5] x86, pci: add dummy pci device for early stage Takao Indoh
2012-11-13 10:01   ` Andrew Murray
2012-11-13 10:57     ` Takao Indoh
2012-11-13  9:07 ` [PATCH v6 2/5] PCI: Define the maximum number of PCI function Takao Indoh
2012-11-13  9:07 ` [PATCH v6 3/5] Make reset_devices available at early stage Takao Indoh
2012-11-13  9:08 ` [PATCH v6 4/5] x86, pci: Reset PCIe devices at boot time Takao Indoh
2012-11-13  9:08 ` [PATCH v6 5/5] x86, pci: Enable PCI INTx when MSI is disabled Takao Indoh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).