Re: PCI hotplug problems: how to debug?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Nov 16, 2009 at 03:07:40PM -0800, Ira W. Snyder wrote:

[ big snip ]

> > 
> > This looks like legacy IDE stuff for a device that is probably built into
> > the southbridge.  Since it lives on PCI bus 0, I suppose these regions
> > should somehow be added as apertures that the host bridge claims.  This
> > is all the sort of stuff that firmware is supposed to handle for you
> > when it builds the host bridge _CRS (if you have ACPI).
> > 
> > I can't think of anything better than just adding these as hard-coded
> > apertures.
> > 
> 
> Ok. This makes sense, they are part of the IDE device, a function of the
> south bridge. Interestingly, they do not show up on the Force computer
> at all, only on the Trenton.
> 
> ===== Force: =====
> iws@labslcor4 ~ $ lspci -vvv -s 00:0f.1
> 00:0f.1 IDE interface: Broadcom OSB4 IDE Controller (prog-if 8a [Master SecP PriP])
> 	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
> 	Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
> 	Latency: 64
> 	Region 4: I/O ports at 1400 [size=16]
> 	Kernel driver in use: Serverworks_IDE
> 
> These I/O ports *do* show up on Bridge 0, where I decoded them to be.
> They are 1000-140c. All of the I/O ports show up correctly in the bridge
> on the Force.
> 
> iws@labslcor4 ~ $ lspci -vvv | grep 'I/O ports'
> 	Region 1: I/O ports at 1080 [size=64]
> 	Region 1: I/O ports at 10c0 [size=64]
> 	Region 1: I/O ports at 1000 [size=128]
> 	Region 4: I/O ports at 1400 [size=16]
> 
> 
> ===== Trenton: =====
> iws@labslcor3 ~ $ lspci -vvv -s 00:0f.1
> 00:0f.1 IDE interface: Broadcom OSB4 IDE Controller (prog-if 8a [Master SecP PriP])
> 	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
> 	Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
> 	Latency: 64
> 	Region 0: [virtual] Memory at 000001f0 (32-bit, non-prefetchable) [size=8]
> 	Region 1: [virtual] Memory at 000003f0 (type 3, non-prefetchable) [size=1]
> 	Region 2: [virtual] Memory at 00000170 (32-bit, non-prefetchable) [size=8]
> 	Region 3: [virtual] Memory at 00000370 (type 3, non-prefetchable) [size=1]
> 	Region 4: I/O ports at ffa0 [size=16]
> 	Kernel driver in use: pata_serverworks
> 
> These I/O ports *do not* show up on Bridge 0, where I decoded them to
> be. Bridge #0 shows: d000-dffc. Bridge #1 shows: e000-effc. All of the
> I/O ports in the system are:
> 
> iws@labslcor3 ~ $ lspci -vvv | grep 'I/O ports'
> 	Region 1: I/O ports at de80 [size=64]
> 	Region 1: I/O ports at df00 [size=64]
> 	Region 4: I/O ports at ffa0 [size=16]
> 
> So the Trenton's BIOS missed the ffa0-ffac range, I guess. Since the
> ranges do not seem to be identical between my two boards, what should I
> do here? The legacy IDE I/O ports don't even show up on the Force.
> 

This patch works on the Trenton, I haven't tried it on the Force to see
if it messed up anything. One thing that does not work is hotplugging
the IDE controller. It fails with the message:

[   89.330650] pci_bus 0000:00: scanning bus
[   89.334518] pci 0000:00:0f.1: found [1166:0211] class 000101 header type 00
[   89.338406] pci 0000:00:0f.1: calling quirk_no_ata_d3+0x0/0x24
[   89.342441] pci 0000:00:0f.1: reg 20: [io  0xffa0-0xffaf]
[   89.346423] pci 0000:00:0f.1: calling quirk_resource_alignment+0x0/0x164
[   89.350504] pci_bus 0000:00: bus scan returning with max=00
[   89.354439] pci 0000:00:0f.1: BAR 4: assigned [io  0xffa0-0xffaf]
[   89.358396] pci 0000:00:0f.1: BAR 4: set to [io  0xffa0-0xffaf] (PCI address [0xffa0-0xffaf]
[   89.363293] pata_serverworks 0000:00:0f.1: device not available (can't reserve [io  0x01f0-0x01f7])
[   89.366497] pata_serverworks: probe of 0000:00:0f.1 failed with error -22
[   89.370652] pci_bus 0000:01: scanning bus
[   89.374483] pci_bus 0000:01: bus scan returning with max=01

This comes from drivers/pci/setup-res.c. Does some quirk need to be
applied to the southbridge as well? I'm not sure exactly what the
failure is, other than resource->parent is NULL.

I'm aware that hotplugging the IDE controller is pretty non-sensical. In
fact, I do not care if the IDE controller works, I do not use it. I boot
entirely over the network. There are no local disks. Still, I think it
should work once we get this right.

We're getting really, really close now. :)

Thanks for all the help over the past few weeks,
Ira


>From d3e0764d1de7ce9e3920d6ae79be67b74d828535 Mon Sep 17 00:00:00 2001
From: Ira W. Snyder <iws@xxxxxxxxxxxxxxxx>
Date: Mon, 16 Nov 2009 08:42:39 -0800
Subject: [PATCH] PCI: read memory ranges out of Broadcom CNB20LE host bridge

Read the memory ranges behind the Broadcom CNB20LE host bridge out of the
hardware. This allows PCI hotplugging to work, since we know which memory
range to allocate PCI BAR's from.

Signed-off-by: Ira W. Snyder <iws@xxxxxxxxxxxxxxxx>
---
 arch/x86/pci/Makefile       |    1 +
 arch/x86/pci/amd_bus.c      |    8 ++++-
 arch/x86/pci/broadcom_bus.c |   70 +++++++++++++++++++++++++++++++++++++++++++
 arch/x86/pci/bus_numa.h     |    4 +--
 4 files changed, 78 insertions(+), 5 deletions(-)
 create mode 100644 arch/x86/pci/broadcom_bus.c

diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index d8a0a62..f762c05 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_X86_NUMAQ)		+= numaq_32.o
 
 obj-y				+= common.o early.o
 obj-y				+= amd_bus.o
+obj-y				+= broadcom_bus.o
 obj-$(CONFIG_X86_64)		+= intel_bus.o
 
 ifeq ($(CONFIG_PCI_DEBUG),y)
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index 995f360..974d5cc 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -17,8 +17,6 @@
  * also get peer root bus resource for io,mmio
  */
 
-#ifdef CONFIG_X86_64
-
 int pci_root_num;
 struct pci_root_info pci_root_info[PCI_ROOT_NR];
 static int found_all_numa_early;
@@ -67,6 +65,8 @@ void x86_pci_root_bus_res_quirks(struct pci_bus *b)
 	}
 }
 
+#ifdef CONFIG_X86_64
+
 #define RANGE_NUM 16
 
 struct res_range {
@@ -119,6 +119,8 @@ static void __init update_range(struct res_range *range, size_t start,
 	}
 }
 
+#endif /* CONFIG_X86_64 */
+
 void __init update_res(struct pci_root_info *info, size_t start,
 			      size_t end, unsigned long flags, int merge)
 {
@@ -168,6 +170,8 @@ addit:
 	info->res_num++;
 }
 
+#ifdef CONFIG_X86_64
+
 struct pci_hostbridge_probe {
 	u32 bus;
 	u32 slot;
diff --git a/arch/x86/pci/broadcom_bus.c b/arch/x86/pci/broadcom_bus.c
new file mode 100644
index 0000000..84ceaf5
--- /dev/null
+++ b/arch/x86/pci/broadcom_bus.c
@@ -0,0 +1,70 @@
+/*
+ * Read address ranges from a Broadcom CNB20LE Host Bridge
+ *
+ * Copyright (c) 2009 Ira W. Snyder <iws@xxxxxxxxxxxxxxxx>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#define DEBUG 1
+
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/pci_x86.h>
+
+#include "bus_numa.h"
+
+static void __devinit cnb20le_res(struct pci_dev *dev)
+{
+	struct pci_root_info *info;
+	unsigned long flags;
+	u16 word1, word2;
+	u32 start, end;
+	u8 fbus, lbus;
+
+	info = &pci_root_info[pci_root_num];
+	pci_root_num++;
+
+	pci_read_config_byte(dev, 0x44, &fbus);
+	pci_read_config_byte(dev, 0x45, &lbus);
+	dev_dbg(&dev->dev, "CNB20LE: busses: %d to %d\n", fbus, lbus);
+
+	info->bus_min = fbus;
+	info->bus_max = lbus;
+
+	pci_read_config_word(dev, 0xc0, &word1);
+	pci_read_config_word(dev, 0xc2, &word2);
+	dev_dbg(&dev->dev, "CNB20LE: noPF 0x%.4x 0x%.4x\n", word1, word2);
+	if (word1 != word2) {
+		start = (word1 << 16) | 0x0000;
+		end   = (word2 << 16) | 0xffff;
+		flags = IORESOURCE_MEM;
+		update_res(info, start, end, flags, 0);
+	}
+
+	pci_read_config_word(dev, 0xc4, &word1);
+	pci_read_config_word(dev, 0xc6, &word2);
+	dev_dbg(&dev->dev, "CNB20LE: PF 0x%.4x 0x%.4x\n", word1, word2);
+	if (word1 != word2) {
+		start = (word1 << 16) | 0x0000;
+		end   = (word2 << 16) | 0xffff;
+		flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+		update_res(info, start, end, flags, 0);
+	}
+
+	pci_read_config_word(dev, 0xd0, &word1);
+	pci_read_config_word(dev, 0xd2, &word2);
+	dev_dbg(&dev->dev, "CNB20LE: IO 0x%.4x 0x%.4x\n", word1, word2);
+	if (word1 != word2) {
+		start = word1;
+		end   = word2;
+		flags = IORESOURCE_IO;
+		update_res(info, start, end, flags, 0);
+	}
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE, cnb20le_res);
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h
index 4ff126a..03ee918 100644
--- a/arch/x86/pci/bus_numa.h
+++ b/arch/x86/pci/bus_numa.h
@@ -1,5 +1,3 @@
-#ifdef CONFIG_X86_64
-
 /*
  * sub bus (transparent) will use entres from 3 to store extra from
  * root, so need to make sure we have enought slot there, Should we
@@ -23,4 +21,4 @@ extern struct pci_root_info pci_root_info[PCI_ROOT_NR];
 
 extern void update_res(struct pci_root_info *info, size_t start,
 			      size_t end, unsigned long flags, int merge);
-#endif
+
-- 
1.5.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux