Skip to contentSkip to conversation

[2.6] PCI Scan all functions

PATCH In review Jake Moilanen 7 participants 8 messages Jan 27, 2004 – Jan 28, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 [2.6] PCI Scan all functions

There are some arch, like PPC64, that need to be able to scan all the PCI functions. The problem comes in on a logically partitioned system where function 0 on a PCI-PCI bridge is assigned to one partition and say function 2 is assiged to another partition. On the second partition, it would appear that function 0 does not exist, but function 2 does. If all the functions are not scanned, everything under function 2 would not be detected.

Thanks,
Jake

drivers/pci/probe.c +3 -1
diff -urpN linux-2.6.1/drivers/pci/probe.c linux-2.6.1-pcibios-scan-all-fns/drivers/pci/probe.c
@@ -7,6 +7,8 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 
+#include <asm/pci.h>
+
 #undef DEBUG
 
 #ifdef DEBUG
@@ -553,7 +555,7 @@ int __devinit pci_scan_slot(struct pci_b
 
 		dev = pci_scan_device(bus, devfn);
 		pci_scan_msi_device(dev);
-		if (func == 0) {
+		if (!pcibios_scan_all_fns() && func == 0) {
 			if (!dev)
 				break;
 		} else {
include/asm-alpha/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-alpha/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-alpha/pci.h
@@ -51,6 +51,7 @@ struct pci_controller {
    bus numbers.  */
 
 #define pcibios_assign_all_busses()	1
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		alpha_mv.min_io_address
 #define PCIBIOS_MIN_MEM		alpha_mv.min_mem_address
include/asm-arm/pci.h +2 -0
diff -urpN linux-2.6.1/include/asm-arm/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-arm/pci.h
@@ -20,6 +20,8 @@
 #endif
 
 
+#define pcibios_scan_all_fns()		0
+
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
include/asm-arm26/pci.h +2 -1
diff -urpN linux-2.6.1/include/asm-arm26/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-arm26/pci.h
@@ -1,5 +1,6 @@
 /* Should not be needed. IDE stupidity */
 /* JMA 18.05.03 - is kinda needed, if only to tell it we don't have a PCI bus */
 
-#define PCI_DMA_BUS_IS_PHYS  0
+#define PCI_DMA_BUS_IS_PHYS  		0
+#define pcibios_scan_all_fns()		0
 
include/asm-generic/pci.h +2 -0
diff -urpN linux-2.6.1/include/asm-generic/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-generic/pci.h
@@ -22,4 +22,6 @@ pcibios_resource_to_bus(struct pci_dev *
 	region->end = res->end;
 }
 
+#define pcibios_scan_all_fns()		0
+
 #endif
include/asm-h8300/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-h8300/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-h8300/pci.h
@@ -8,6 +8,7 @@
  */
 
 #define pcibios_assign_all_busses()	0
+#define pcibios_scan_all_fns()		0
 
 extern inline void pcibios_set_master(struct pci_dev *dev)
 {
include/asm-i386/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-i386/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-i386/pci.h
@@ -15,6 +15,7 @@ extern unsigned int pcibios_assign_all_b
 #else
 #define pcibios_assign_all_busses()	0
 #endif
+#define pcibios_scan_all_fns()		0
 
 extern unsigned long pci_mem_start;
 #define PCIBIOS_MIN_IO		0x1000
include/asm-ia64/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-ia64/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-ia64/pci.h
@@ -16,6 +16,7 @@
  * loader.
  */
 #define pcibios_assign_all_busses()     0
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
include/asm-m68k/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-m68k/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-m68k/pci.h
@@ -36,6 +36,7 @@ struct pci_bus_info
 };
 
 #define pcibios_assign_all_busses()	0
+#define pcibios_scan_all_fns()		0
 
 extern inline void pcibios_set_master(struct pci_dev *dev)
 {
include/asm-m68knommu/pci.h +2 -0
diff -urpN linux-2.6.1/include/asm-m68knommu/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-m68knommu/pci.h
@@ -11,6 +11,8 @@
 #define PCIBIOS_MIN_IO		0x100
 #define PCIBIOS_MIN_MEM		0x00010000
 
+#define pcibios_scan_all_fns()		0
+
 /*
  * Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
include/asm-mips/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-mips/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-mips/pci.h
@@ -20,6 +20,7 @@ extern unsigned int pcibios_assign_all_b
 #else
 #define pcibios_assign_all_busses()	0
 #endif
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
include/asm-parisc/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-parisc/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-parisc/pci.h
@@ -174,6 +174,7 @@ extern inline void pcibios_register_hba(
 **   to zero for legacy platforms and one for PAT platforms.
 */
 #define pcibios_assign_all_busses()     (pdc_type == PDC_TYPE_PAT)
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO          0x10
 #define PCIBIOS_MIN_MEM         0x1000 /* NBPG - but pci/setup-res.c dies */
include/asm-ppc/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-ppc/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-ppc/pci.h
@@ -26,6 +26,7 @@ struct pci_dev;
 extern int pci_assign_all_busses;
 
 #define pcibios_assign_all_busses()	(pci_assign_all_busses)
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
include/asm-ppc64/pci.h +6 -0
diff -urpN linux-2.6.1/include/asm-ppc64/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-ppc64/pci.h
@@ -19,6 +19,12 @@
 #define PCIBIOS_MIN_IO		0x1000
 #define PCIBIOS_MIN_MEM		0x10000000
 
+/*
+ * ppc64 can have multifunction devices that do not respond to function 0. 
+ * In this case we must scan all functions.
+ */
+#define pcibios_scan_all_fns()     1
+
 static inline void pcibios_set_master(struct pci_dev *dev)
 {
 	/* No special bus mastering setup handling */
include/asm-sh/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-sh/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-sh/pci.h
@@ -12,6 +12,7 @@
    or architectures with incomplete PCI setup by the loader */
 
 #define pcibios_assign_all_busses()	1
+#define pcibios_scan_all_fns()		0
 
 #if defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 /* These are currently the correct values for the STM overdrive board. 
include/asm-sparc/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-sparc/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-sparc/pci.h
@@ -8,6 +8,7 @@
  * or architectures with incomplete PCI setup by the loader.
  */
 #define pcibios_assign_all_busses()	0
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		0UL
 #define PCIBIOS_MIN_MEM		0UL
include/asm-sparc64/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-sparc64/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-sparc64/pci.h
@@ -11,6 +11,7 @@
  * or architectures with incomplete PCI setup by the loader.
  */
 #define pcibios_assign_all_busses()	0
+#define pcibios_scan_all_fns()		0
 
 #define PCIBIOS_MIN_IO		0UL
 #define PCIBIOS_MIN_MEM		0UL
include/asm-um/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-um/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-um/pci.h
@@ -2,5 +2,6 @@
 #define __UM_PCI_H
 
 #define PCI_DMA_BUS_IS_PHYS     (1)
+#define pcibios_scan_all_fns()		0
 
 #endif
include/asm-v850/pci.h +2 -0
diff -urpN linux-2.6.1/include/asm-v850/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-v850/pci.h
@@ -17,6 +17,8 @@
 /* Get any platform-dependent definitions.  */
 #include <asm/machdep.h>
 
+#define pcibios_scan_all_fns()		0
+
 /* Generic declarations.  */
 
 struct scatterlist;
include/asm-x86_64/pci.h +1 -0
diff -urpN linux-2.6.1/include/asm-x86_64/pci.h linux-2.6.1-pcibios-scan-all-fns/include/asm-x86_64/pci.h
@@ -17,6 +17,7 @@ extern unsigned int pcibios_assign_all_b
 #else
 #define pcibios_assign_all_busses()	0
 #endif
+#define pcibios_scan_all_fns()		0
 
 extern int no_iommu, force_iommu;
 
#1 lore raw
Quoted 7 lines · Jake Moilanen

There are some arch, like PPC64, that need to be able to scan all the PCI functions. The problem comes in on a logically partitioned system where function 0 on a PCI-PCI bridge is assigned to one partition and say function 2 is assiged to another partition. On the second partition, it would appear that function 0 does not exist, but function 2 does. If all the functions are not scanned, everything under function 2 would not be detected.

Heh, I think the PPC64 people need to get together and all talk about this, as I just got a different patch, that solves much the same problem from John Rose (it's on the linuxppc64 mailing list.)

Can you two get together and not patch the same section of code to do the same thing in different ways?

thanks,

greg k-h

#2 lore raw
Quoted 10 lines · Greg KH
Quoted 7 lines · Jake Moilanen

There are some arch, like PPC64, that need to be able to scan all the PCI functions. The problem comes in on a logically partitioned system where function 0 on a PCI-PCI bridge is assigned to one partition and say function 2 is assiged to another partition. On the second partition, it would appear that function 0 does not exist, but function 2 does. If all the functions are not scanned, everything under function 2 would not be detected.

Quoted 6 lines

Heh, I think the PPC64 people need to get together and all talk about this, as I just got a different patch, that solves much the same problem from John Rose (it's on the linuxppc64 mailing list.)

Can you two get together and not patch the same section of code to do the same thing in different ways?

While we're on the topic, what's with the below patch? I've had it in -mm for ages but apparently there's some disagreement over it.

From: Anton Blanchard <[email protected]>

We have IO BARs on ppc64 machines that begin at address 0. The current pci probe code will ignore anything that starts at 0. Remove these checks.

---

 drivers/pci/probe.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/pci/probe.c renamed from drivers/pci/probe.c~ppc64-bar-0-fix +3 -3
diff -puN drivers/pci/probe.c~ppc64-bar-0-fix drivers/pci/probe.c
@@ -176,7 +176,7 @@ void __devinit pci_read_bridge_bases(str
 		limit |= (io_limit_hi << 16);
 	}
 
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
 		res->start = base;
 		res->end = limit + 0xfff;
@@ -187,7 +187,7 @@ void __devinit pci_read_bridge_bases(str
 	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
 	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
 	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
 		res->start = base;
 		res->end = limit + 0xfffff;
@@ -213,7 +213,7 @@ void __devinit pci_read_bridge_bases(str
 		}
 #endif
 	}
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
 		res->start = base;
 		res->end = limit + 0xfffff;

_

#3 lore raw
Quoted 15 lines · Andrew Morton
Quoted 14 lines · Greg KH
Quoted 7 lines · Jake Moilanen

There are some arch, like PPC64, that need to be able to scan all the PCI functions. The problem comes in on a logically partitioned system where function 0 on a PCI-PCI bridge is assigned to one partition and say function 2 is assiged to another partition. On the second partition, it would appear that function 0 does not exist, but function 2 does. If all the functions are not scanned, everything under function 2 would not be detected.

Heh, I think the PPC64 people need to get together and all talk about this, as I just got a different patch, that solves much the same problem from John Rose (it's on the linuxppc64 mailing list.)

Quoted 5 lines
Quoted 2 lines

Can you two get together and not patch the same section of code to do the same thing in different ways?

While we're on the topic, what's with the below patch? I've had it in -mm for ages but apparently there's some disagreement over it.

It looks ok to me, but Linus and Ivan were the ones disagreeing over how to implement this correctly, as they understand the resource management logic a lot better than I.

They should be the ones to say if this is ok or not.

thanks,

greg k-h

Quoted 44 lines

From: Anton Blanchard <[email protected]>

We have IO BARs on ppc64 machines that begin at address 0. The current pci probe code will ignore anything that starts at 0. Remove these checks.

---

 drivers/pci/probe.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff -puN drivers/pci/probe.c~ppc64-bar-0-fix drivers/pci/probe.c

drivers/pci/probe.c renamed from drivers/pci/probe.c~ppc64-bar-0-fix +3 -3
@@ -176,7 +176,7 @@ void __devinit pci_read_bridge_bases(str
 		limit |= (io_limit_hi << 16);
 	}
 
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
 		res->start = base;
 		res->end = limit + 0xfff;
@@ -187,7 +187,7 @@ void __devinit pci_read_bridge_bases(str
 	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
 	base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
 	limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
 		res->start = base;
 		res->end = limit + 0xfffff;
@@ -213,7 +213,7 @@ void __devinit pci_read_bridge_bases(str
 		}
 #endif
 	}
-	if (base && base <= limit) {
+	if (base <= limit) {
 		res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
 		res->start = base;
 		res->end = limit + 0xfffff;

_

#4 lore raw
Quoted 2 lines · Greg KH

Review

Quoted 2 lines
(quoted diff) +1 -1
-	if (base && base <= limit) {
+	if (base <= limit) {

I think the patch is safe. Architectures that don't accept bridge windows (and regular BARs) at bus address 0 already have that check elsewhere.
For example, in arch/i386/pci/i386.c:pcibios_allocate_bus_resources():
...

			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
				r = &dev->resource[idx];
				if (!r->start)
				    ^^^^^^^^^
					continue;

...

Ivan.

#5 lore raw
In reply to Andrew Morton
Quoted 3 lines · Andrew Morton

While we're on the topic, what's with the below patch? I've had it in -mm for ages but apparently there's some disagreement over it.

I'd be very worried, since I'm pretty sure that there _are_ devices where "zero means disabled".

On the other hand, the resource management should do the right thing anyway, so I guess it should be safe. Especially if it's been in -mm for a long time..

Linus

#6 lore raw
In reply to Greg KH

Hi-

Quoted 6 lines

Heh, I think the PPC64 people need to get together and all talk about this, as I just got a different patch, that solves much the same problem from John Rose (it's on the linuxppc64 mailing list.)

Can you two get together and not patch the same section of code to do the same thing in different ways?

These patches don't address the same problem. Jake's problem has to do with pci_scan_slot() ending too soon when going from function 0->7 at boot time. My problem has to do with pci_scan_slot() going too far from function 0->7 at dlpar add time. Greg, will follow up with you outside of this thread.

Thanks-
John

Signature · 1 line
John Rose <[email protected]>
#7 lore raw
In reply to Jake Moilanen

Hello!

Quoted 7 lines

There are some arch, like PPC64, that need to be able to scan all the PCI functions. The problem comes in on a logically partitioned system where function 0 on a PCI-PCI bridge is assigned to one partition and say function 2 is assiged to another partition. On the second partition, it would appear that function 0 does not exist, but function 2 does. If all the functions are not scanned, everything under function 2 would not be detected.

Enabling scan of all functions globally is probably going to cause troubles, because there are single-function devices which respond to all function numbers. You need to enable this quirk selectively.

Have a nice fortnight

Signature · 3 lines
Martin `MJ' Mares   <[email protected]>   http://atrey.karlin.mff.cuni.cz/~mj/
Faculty of Math and Physics, Charles University, Prague, Czech Rep., Earth
"God doesn't play dice."    -- Albert Einstein