linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-28  9:38 Durairaj, Sundarapandian
  2004-01-28 14:42 ` Vladimir Kondratiev
  2004-01-28 15:18 ` Matthew Wilcox
  0 siblings, 2 replies; 43+ messages in thread
From: Durairaj, Sundarapandian @ 2004-01-28  9:38 UTC (permalink / raw)
  To: linux-kernel, linux-pci
  Cc: torvalds, alan, greg, Andi Kleen, akpm, mj, Kondratiev, Vladimir,
	Seshadri, Harinarayanan, Nakajima, Jun, Durairaj, Sundarapandian

[-- Attachment #1: Type: text/plain, Size: 730 bytes --]

Hi All, 

Thanks for your comments. I am posting this patch after incorporating
the review comments.

Please find the attached patch file. Please review this and send your
comments.

Thanks,
Sundar

Note:
This is the patch on PCI Express Enhanced configuration for 2.6.0 test11
kernel following up to the Vladimir (Vladimir.Kondratiev@intel.com) and
Harinarayanan (Harinarayanan.Seshadri@intel.com)  and my previous
patches .
I tested it on our i386 platform. 

This patch also implements a mechanism for the kernel to find the
chipset specific mmcfg base address. The kernel will detect the base
address of the chipset through the ACPI table entry and based on that
the PCI subsystem will be initialized.  

[-- Attachment #2: mcfg_2.6.lkml.patch --]
[-- Type: application/octet-stream, Size: 15758 bytes --]

diff -Naur linux-2.6.0/arch/i386/Kconfig linux_pciexpress/arch/i386/Kconfig
--- linux-2.6.0/arch/i386/Kconfig	2003-12-18 08:28:16.000000000 +0530
+++ linux_pciexpress/arch/i386/Kconfig	2004-01-28 12:04:20.000000000 +0530
@@ -959,7 +959,7 @@
 endmenu
 
 
-menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA, PCI_EXPRESS)"
 
 config X86_VISWS_APIC
 	bool
@@ -976,6 +976,18 @@
 	depends on SMP && !(X86_VISWS || X86_VOYAGER)
 	default y
 
+config PCI_EXPRESS
+	bool "PCI_EXPRESS (EXPERIMENTAL)" 
+	depends on EXPERIMENTAL && ACPI_BOOT
+	help
+	  PCI Express extends the configuration space from 256 bytes to
+	  4k bytes. It also defines an enhanced configuration mechanism
+	  to access the extended configuration space. With this option, 
+	  you can specify that Linux will first attempt to access the 
+	  PCI configuration space through enhanced config access 
+	  mechanism (will work only on PCI Express based system)
+	  otherwise other standard PCI access mechanism will be used.
+
 config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
diff -Naur linux-2.6.0/arch/i386/kernel/acpi/boot.c linux_pciexpress/arch/i386/kernel/acpi/boot.c
--- linux-2.6.0/arch/i386/kernel/acpi/boot.c	2003-12-18 08:29:29.000000000 +0530
+++ linux_pciexpress/arch/i386/kernel/acpi/boot.c	2004-01-28 11:43:28.000000000 +0530
@@ -93,6 +93,27 @@
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_PCI_EXPRESS
+static int __init acpi_parse_mcfg
+			(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg	*mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table
+						(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+	if (mcfg->base_address)
+		mmcfg_base_address = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_PCI_EXPRESS */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -508,6 +529,22 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
+#ifdef CONFIG_PCI_EXPRESS
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MCFG not present\n");
+		return 0;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
+		return result;
+	}
+	else if (result > 1) {
+		printk(KERN_WARNING PREFIX
+			"Multiple MCFG tables exist\n");
+	}
+#endif /* CONFIG_PCI_EXPRESS */
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
diff -Naur linux-2.6.0/arch/i386/pci/common.c linux_pciexpress/arch/i386/pci/common.c
--- linux-2.6.0/arch/i386/pci/common.c	2003-12-18 08:28:46.000000000 +0530
+++ linux_pciexpress/arch/i386/pci/common.c	2004-01-28 11:51:38.000000000 +0530
@@ -19,7 +19,8 @@
 extern  void pcibios_sort(void);
 #endif
 
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2;
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2
+				 | PCI_PROBE_ENHANCED;
 
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
@@ -197,6 +198,12 @@
 		return NULL;
 	}
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	else if (!strcmp(str, "nopciexpress")) {
+		pci_probe &= ~PCI_PROBE_ENHANCED;
+		return NULL;
+	}
+#endif
 #ifdef CONFIG_ACPI_PCI
 	else if (!strcmp(str, "noacpi")) {
 		pci_probe |= PCI_NO_ACPI_ROUTING;
diff -Naur linux-2.6.0/arch/i386/pci/direct.c linux_pciexpress/arch/i386/pci/direct.c
--- linux-2.6.0/arch/i386/pci/direct.c	2003-12-18 08:28:28.000000000 +0530
+++ linux_pciexpress/arch/i386/pci/direct.c	2004-01-28 11:27:07.000000000 +0530
@@ -167,6 +167,73 @@
 };
 
 
+#ifdef CONFIG_PCI_EXPRESS
+/*
+ * We map full Page size on each PCI Express request. Incidentally that's 
+ * the size we have for config space too in PCI Express devices.
+ * On PCI Express capable platform, at the time of kernel initialization
+ * the OS would have scanned for MCFG table and set this variable to 
+ * appropriate value. If PCI Express not supported the variable will 
+ * have 0 value
+ */
+u32 mmcfg_base_address;
+
+/*
+ * Variable used to store the virtual  address of fixed PTE
+ */
+char *mmcfg_virt_addr;
+
+/*
+ * Variable used to store the base address of the last PCI Express device
+ * accessed.
+ */
+u32 pcie_last_accessed_device;
+
+static int pci_express_conf_read(int seg, int bus,
+		int devfn, int reg, int len, u32 *value)
+{
+	if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) {
+		printk(KERN_ERR "pci_express_conf_read: "
+					"Invalid Parameter\n");
+  		return -EINVAL;
+	}
+
+	/* Shoot misaligned transaction now */
+	if (reg & (len-1)) {
+		printk(KERN_ERR "pci_express_conf_read: "
+					"misaligned transaction\n");
+  		return -EINVAL;
+	}
+	pci_express_read(bus, devfn, reg, len, value);
+
+	return 0;
+}
+ 
+static int pci_express_conf_write(int seg, int bus, 
+			int devfn, int reg, int len, u32 value)
+{
+	if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
+		printk(KERN_ERR "pci_express_conf_write: "
+					"Invalid Parameter\n");
+		return -EINVAL;
+	}
+
+	/* Shoot misaligned transaction now */
+	if (reg & (len-1)) {
+		printk(KERN_ERR "pci_express_conf_write: "
+					"misaligned transaction\n");
+  		return -EINVAL;
+	}
+	pci_express_write(bus, devfn, reg, len, value);
+	return 0;
+}
+
+static struct pci_raw_ops pci_express_conf = {
+	.read   =	pci_express_conf_read,
+	.write  =	pci_express_conf_write,
+};
+#endif /* CONFIG_PCI_EXPRESS */
+
 /*
  * Before we decide to use direct hardware access mechanisms, we try to do some
  * trivial checks to ensure it at least _seems_ to be working -- we just test
@@ -244,7 +311,30 @@
 static int __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
+	
+#ifdef CONFIG_PCI_EXPRESS
+	if ((pci_probe & PCI_PROBE_ENHANCED) == 0)
+		goto type1;
+	/*
+ 	 * Check if platform we are running is PCI Express capable
+  	 */
+	if (mmcfg_base_address == 0) {
+		printk(KERN_INFO 
+		      "MCFG table entry is not found in ACPI tables....\n"
+		      "Not enabling Enhanced Configuration....\n");
+		goto type1;
+	}
 
+	/* Calculate the virtual address of the PTE */
+	mmcfg_virt_addr = (char *)fix_to_virt(FIX_PCIE_MCFG);
+
+	if (pci_sanity_check(&pci_express_conf)) {
+		printk(KERN_INFO "PCI: Using config type PCIExp\n");
+		raw_pci_ops = &pci_express_conf;
+		return 0;
+	}
+type1:
+#endif /* CONFIG_PCI_EXPRESS */
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
 	region = request_region(0xCF8, 8, "PCI conf1");
diff -Naur linux-2.6.0/arch/i386/pci/Makefile linux_pciexpress/arch/i386/pci/Makefile
--- linux-2.6.0/arch/i386/pci/Makefile	2003-12-18 08:28:57.000000000 +0530
+++ linux_pciexpress/arch/i386/pci/Makefile	2004-01-26 13:32:28.000000000 +0530
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_PCI_EXPRESS)	+= direct.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI_PCI)		+= acpi.o
diff -Naur linux-2.6.0/arch/i386/pci/pci.h linux_pciexpress/arch/i386/pci/pci.h
--- linux-2.6.0/arch/i386/pci/pci.h	2003-12-18 08:28:57.000000000 +0530
+++ linux_pciexpress/arch/i386/pci/pci.h	2004-01-26 13:32:28.000000000 +0530
@@ -15,6 +15,11 @@
 #define PCI_PROBE_BIOS		0x0001
 #define PCI_PROBE_CONF1		0x0002
 #define PCI_PROBE_CONF2		0x0004
+#ifdef CONFIG_PCI_EXPRESS
+#define PCI_PROBE_ENHANCED	0x0008
+#else
+#define PCI_PROBE_ENHANCED 	0x0
+#endif
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_NO_CHECKS		0x0400
diff -Naur linux-2.6.0/drivers/acpi/tables.c linux_pciexpress/drivers/acpi/tables.c
--- linux-2.6.0/drivers/acpi/tables.c	2003-12-18 08:28:46.000000000 +0530
+++ linux_pciexpress/drivers/acpi/tables.c	2004-01-26 13:31:51.000000000 +0530
@@ -58,6 +58,7 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 /* System Description Table (RSDT/XSDT) */
diff -Naur linux-2.6.0/drivers/pci/pci.c linux_pciexpress/drivers/pci/pci.c
--- linux-2.6.0/drivers/pci/pci.c	2003-12-18 08:28:38.000000000 +0530
+++ linux_pciexpress/drivers/pci/pci.c	2004-01-26 13:31:40.000000000 +0530
@@ -90,6 +90,8 @@
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
  *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI-EXP
+
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
diff -Naur linux-2.6.0/drivers/pci/probe.c linux_pciexpress/drivers/pci/probe.c
--- linux-2.6.0/drivers/pci/probe.c	2003-12-18 08:29:06.000000000 +0530
+++ linux_pciexpress/drivers/pci/probe.c	2004-01-28 12:06:39.000000000 +0530
@@ -17,6 +17,8 @@
 
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
 
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
@@ -479,6 +481,22 @@
 	kfree(pci_dev);
 }
 
+/* 
+ * pci_cfg_space_size - get the configuration space size of the PCI device
+ */
+static int pci_cfg_space_size(struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI_EXPRESS
+	/* Find whether the device is PCI Express device */
+	int is_pci_express_dev = 
+		pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (is_pci_express_dev)
+		return PCI_CFG_SPACE_EXP_SIZE;
+	else
+#endif
+	return PCI_CFG_SPACE_SIZE; 
+}
+
 /*
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
@@ -515,6 +533,7 @@
 	dev->multifunction = !!(hdr_type & 0x80);
 	dev->vendor = l & 0xffff;
 	dev->device = (l >> 16) & 0xffff;
+	dev->cfg_size = pci_cfg_space_size(dev);
 
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
diff -Naur linux-2.6.0/drivers/pci/proc.c linux_pciexpress/drivers/pci/proc.c
--- linux-2.6.0/drivers/pci/proc.c	2003-12-18 08:28:57.000000000 +0530
+++ linux_pciexpress/drivers/pci/proc.c	2004-01-26 15:45:34.000000000 +0530
@@ -16,14 +16,15 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
-#define PCI_CFG_SPACE_SIZE 256
-
 static int proc_initialized;	/* = 0 */
 
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
 	loff_t new = -1;
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
 
 	lock_kernel();
 	switch (whence) {
@@ -34,11 +35,11 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
-		new = PCI_CFG_SPACE_SIZE + off;
+		new = dev->cfg_size + off;
 		break;
 	}
 	unlock_kernel();
-	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
+	if (new < 0 || new > dev->cfg_size)
 		return -EINVAL;
 	return (file->f_pos = new);
 }
@@ -59,7 +60,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+ 		size = dev->cfg_size;
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -133,13 +134,14 @@
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
 	int cnt;
+	int size = dev->cfg_size;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -401,7 +403,7 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+	e->size = dev->cfg_size;
 
 	return 0;
 }
diff -Naur linux-2.6.0/include/asm-i386/fixmap.h linux_pciexpress/include/asm-i386/fixmap.h
--- linux-2.6.0/include/asm-i386/fixmap.h	2003-12-18 08:28:06.000000000 +0530
+++ linux_pciexpress/include/asm-i386/fixmap.h	2004-01-26 13:33:49.000000000 +0530
@@ -67,6 +67,9 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings */
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	FIX_PCIE_MCFG,
+#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
diff -Naur linux-2.6.0/include/asm-i386/pci.h linux_pciexpress/include/asm-i386/pci.h
--- linux-2.6.0/include/asm-i386/pci.h	2003-12-18 08:28:47.000000000 +0530
+++ linux_pciexpress/include/asm-i386/pci.h	2004-01-28 11:33:51.000000000 +0530
@@ -96,4 +96,76 @@
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
+#ifdef CONFIG_PCI_EXPRESS
+extern spinlock_t pci_config_lock;
+
+/*
+ * Variable used to store the base address of the last PCI Express device
+ * accessed.
+ */
+extern u32 pcie_last_accessed_device;
+
+/*
+ * Variable used to store the base address of the chipset
+ */
+extern u32 mmcfg_base_address;
+
+/*
+ * Variable used to store the virtual  address of fixed PTE
+ */
+extern char *mmcfg_virt_addr;
+
+static inline void pci_exp_set_dev_base(int bus, int devfn)
+{
+	u32 dev_base = 
+		mmcfg_base_address | (bus << 20) | (devfn << 12);
+	if (dev_base != pcie_last_accessed_device) {
+		pcie_last_accessed_device = dev_base;
+		set_fixmap(FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static inline void pci_express_read(int bus, int devfn, int reg, 
+		int len, u32 *value)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, devfn);
+ 	switch (len) {
+        case 1:
+		*value = (u8)readb(mmcfg_virt_addr + reg);
+		break;
+        case 2:
+		*value = (u16)readw(mmcfg_virt_addr + reg);
+		break;
+        case 4:
+		*value = (u32)readl(mmcfg_virt_addr + reg);
+		break;
+	}
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+
+static inline void pci_express_write(int bus, int devfn, int reg, 
+	int len, u32 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, devfn);
+	switch (len) {
+		case 1:
+			writeb(value, mmcfg_virt_addr + reg);
+			break;
+		case 2:
+			writew(value, mmcfg_virt_addr + reg);
+			break;
+	        case 4:
+			writel(value, mmcfg_virt_addr + reg);
+	                break;
+     	}
+	/* Dummy read to flush PCI write */
+	readl(mmcfg_virt_addr);
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+#endif /* CONFIG_PCI_EXPRESS */
 #endif /* __i386_PCI_H */
diff -Naur linux-2.6.0/include/linux/acpi.h linux_pciexpress/include/linux/acpi.h
--- linux-2.6.0/include/linux/acpi.h	2003-12-18 08:27:58.000000000 +0530
+++ linux_pciexpress/include/linux/acpi.h	2004-01-26 13:33:09.000000000 +0530
@@ -317,6 +317,13 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+struct acpi_table_mcfg {
+	struct acpi_table_header 	header;
+	u8	reserved[8];
+	u32	base_address;
+	u32	base_reserved;
+} __attribute__ ((packed));
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +345,7 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
@@ -437,4 +445,7 @@
 
 #endif /*!CONFIG_ACPI_INTERPRETER*/
 
+#ifdef CONFIG_PCI_EXPRESS
+extern u32 mmcfg_base_address;
+#endif
 #endif /*_LINUX_ACPI_H*/
diff -Naur linux-2.6.0/include/linux/pci.h linux_pciexpress/include/linux/pci.h
--- linux-2.6.0/include/linux/pci.h	2003-12-18 08:28:49.000000000 +0530
+++ linux_pciexpress/include/linux/pci.h	2004-01-26 15:47:23.000000000 +0530
@@ -198,6 +198,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI-Express */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list */
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16 bits) */
 #define PCI_CAP_SIZEOF		4
@@ -424,6 +425,7 @@
 #define PCI_NAME_HALF	__stringify(20)	/* less than half to handle slop */
 	char		pretty_name[PCI_NAME_SIZE];	/* pretty name for users to see */
 #endif
+	int cfg_size;
 };
 
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)

^ permalink raw reply	[flat|nested] 43+ messages in thread
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-30 16:58 Nakajima, Jun
  0 siblings, 0 replies; 43+ messages in thread
From: Nakajima, Jun @ 2004-01-30 16:58 UTC (permalink / raw)
  To: Greg KH, Durairaj, Sundarapandian, Kondratiev, Vladimir,
	Seshadri, Harinarayanan
  Cc: Matthew Wilcox, Kernel Mailing List, linux-pci

> Also, can someone from Intel test out Matthew's patch to make sure it
> works properly for them on their hardware?  It's much cleaner than the
> last patch submitted by you all :)

Okay I'll make sure it happens.

Jun

> -----Original Message-----
> From: Greg KH [mailto:greg@kroah.com]
> Sent: Friday, January 30, 2004 8:33 AM
> To: Durairaj, Sundarapandian; Kondratiev, Vladimir; Seshadri,
> Harinarayanan; Nakajima, Jun
> Cc: Matthew Wilcox; Kernel Mailing List; linux-
> pci@atrey.karlin.mff.cuni.cz
> Subject: Re: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
> 
> On Thu, Jan 29, 2004 at 10:09:52AM -0800, Greg KH wrote:
> > On Thu, Jan 29, 2004 at 08:05:52AM -0800, Linus Torvalds wrote:
> > >
> > > That said, this patch looks perfectly acceptable to me. With some
> testing,
> > > I'd take it through Greg or -mm.
> >
> > It's looking much better.  But I _really_ want to actually test this
on
> > real hardware.  As no one is shipping PCI Express hardware yet,
there is
> > no rush to get this patch into the kernel tree.
> 
> Also, can someone from Intel test out Matthew's patch to make sure it
> works properly for them on their hardware?  It's much cleaner than the
> last patch submitted by you all :)
> 
> thanks,
> 
> greg k-h

^ permalink raw reply	[flat|nested] 43+ messages in thread
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-29 11:32 Durairaj, Sundarapandian
  2004-01-29 15:09 ` Matthew Wilcox
  0 siblings, 1 reply; 43+ messages in thread
From: Durairaj, Sundarapandian @ 2004-01-29 11:32 UTC (permalink / raw)
  To: linux-kernel, linux-pci
  Cc: torvalds, alan, greg, Andi Kleen, akpm, mj, Kondratiev, Vladimir,
	Seshadri, Harinarayanan, Nakajima, Jun, Durairaj, Sundarapandian

Hi All,

Thanks for the comments.

Please review this updated patch and send your comments.

Thanks,
Sundar

Note:
This is the patch on PCI Express Enhanced configuration for 2.6.0 test11
kernel following up to the Vladimir (Vladimir.Kondratiev@intel.com) and
Harinarayanan (Harinarayanan.Seshadri@intel.com)  and my previous
patches .
I tested it on our i386 platform. 

This patch also implements a mechanism for the kernel to find the
chipset specific mmcfg base address. The kernel will detect the base
address of the chipset through the ACPI table entry and based on that
the PCI subsystem will be initialized.  

diff -Naur linux-2.6.0/arch/i386/Kconfig
linux_pciexpress/arch/i386/Kconfig
--- linux-2.6.0/arch/i386/Kconfig	2003-12-18 08:28:16.000000000
+0530
+++ linux_pciexpress/arch/i386/Kconfig	2004-01-29 16:50:56.000000000
+0530
@@ -1020,6 +1020,18 @@
 
 endchoice
 
+config PCI_EXPRESS
+	bool "PCI_EXPRESS (EXPERIMENTAL)" 
+	depends on EXPERIMENTAL && PCI
+	select ACPI_BOOT
+	help
+	  PCI Express is the next generation PCI architecture that
supports
+	  the configuration space size of 4K bytes. With this option, 
+	  Linux will first attempt to access the configuration space
through 
+	  enhanced config access mechanism (will work only on 
+	  PCI Express based system) otherwise other standard PCI access 
+	  mechanism will be used.
+
 config PCI_BIOS
 	bool
 	depends on !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY)
diff -Naur linux-2.6.0/arch/i386/kernel/acpi/boot.c
linux_pciexpress/arch/i386/kernel/acpi/boot.c
--- linux-2.6.0/arch/i386/kernel/acpi/boot.c	2003-12-18
08:29:29.000000000 +0530
+++ linux_pciexpress/arch/i386/kernel/acpi/boot.c	2004-01-29
16:14:43.000000000 +0530
@@ -93,6 +93,27 @@
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_PCI_EXPRESS
+static int __init acpi_parse_mcfg
+			(unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg	*mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table
+						(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+	if (mcfg->base_address)
+		mmcfg_base_address = mcfg->base_address;
+
+	return 0;
+}
+#endif /* CONFIG_PCI_EXPRESS */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -508,6 +529,20 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
+#ifdef CONFIG_PCI_EXPRESS
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MCFG not present\n");
+		return 0;
+	} else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
+		return result;
+	} else if (result > 1) {
+		printk(KERN_WARNING PREFIX
+			"Multiple MCFG tables exist\n");
+	}
+#endif /* CONFIG_PCI_EXPRESS */
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
diff -Naur linux-2.6.0/arch/i386/pci/common.c
linux_pciexpress/arch/i386/pci/common.c
--- linux-2.6.0/arch/i386/pci/common.c	2003-12-18 08:28:46.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/common.c	2004-01-29
16:14:45.000000000 +0530
@@ -19,7 +19,8 @@
 extern  void pcibios_sort(void);
 #endif
 
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 |
PCI_PROBE_CONF2;
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 |
PCI_PROBE_CONF2
+				 | PCI_PROBE_ENHANCED;
 
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
@@ -197,6 +198,12 @@
 		return NULL;
 	}
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	else if (!strcmp(str, "nopciexpress")) {
+		pci_probe &= ~PCI_PROBE_ENHANCED;
+		return NULL;
+	}
+#endif
 #ifdef CONFIG_ACPI_PCI
 	else if (!strcmp(str, "noacpi")) {
 		pci_probe |= PCI_NO_ACPI_ROUTING;
diff -Naur linux-2.6.0/arch/i386/pci/direct.c
linux_pciexpress/arch/i386/pci/direct.c
--- linux-2.6.0/arch/i386/pci/direct.c	2003-12-18 08:28:28.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/direct.c	2004-01-29
16:14:45.000000000 +0530
@@ -167,6 +167,60 @@
 };
 
 
+#ifdef CONFIG_PCI_EXPRESS
+/*
+ * We map full Page size on each PCI Express request. Incidentally
that's 
+ * the size we have for config space too in PCI Express devices.
+ * On PCI Express capable platform, at the time of kernel
initialization
+ * the OS would have scanned for MCFG table and set this variable to 
+ * appropriate value. If PCI Express not supported the variable will 
+ * have 0 value
+ */
+u32 mmcfg_base_address;
+
+/*
+ * Variable used to store the virtual  address of fixed PTE
+ */
+char *mmcfg_virt_addr;
+
+/*
+ * Variable used to store the base address of the last PCI Express
device
+ * accessed.
+ */
+u32 pcie_last_accessed_device;
+
+static int pci_express_conf_read(int seg, int bus,
+		int devfn, int reg, int len, u32 *value)
+{
+	if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) {
+		printk(KERN_ERR "%s: Invalid Parameter\n",
+				__FUNCTION__);
+  		return -EINVAL;
+	}
+	pci_express_read(bus, devfn, reg, len, value);
+
+	return 0;
+}
+ 
+static int pci_express_conf_write(int seg, int bus, 
+			int devfn, int reg, int len, u32 value)
+{
+	if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
+		printk(KERN_ERR "%s: Invalid Parameter\n",
+				__FUNCTION__);
+		return -EINVAL;
+	}
+	pci_express_write(bus, devfn, reg, len, value);
+
+	return 0;
+}
+
+static struct pci_raw_ops pci_express_conf = {
+	.read   =	pci_express_conf_read,
+	.write  =	pci_express_conf_write,
+};
+#endif /* CONFIG_PCI_EXPRESS */
+
 /*
  * Before we decide to use direct hardware access mechanisms, we try to
do some
  * trivial checks to ensure it at least _seems_ to be working -- we
just test
@@ -244,7 +298,30 @@
 static int __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
+	
+#ifdef CONFIG_PCI_EXPRESS
+	if ((pci_probe & PCI_PROBE_ENHANCED) == 0)
+		goto type1;
+	/*
+ 	 * Check if platform we are running is PCI Express capable
+  	 */
+	if (mmcfg_base_address == 0) {
+		printk(KERN_INFO 
+		      "MCFG table entry is not found in ACPI
tables....\n"
+		      "Not enabling Enhanced Configuration....\n");
+		goto type1;
+	}
 
+	/* Calculate the virtual address of the PTE */
+	mmcfg_virt_addr = (char *)fix_to_virt(FIX_PCIE_MCFG);
+
+	if (pci_sanity_check(&pci_express_conf)) {
+		printk(KERN_INFO "PCI: Using config type PCIExp\n");
+		raw_pci_ops = &pci_express_conf;
+		return 0;
+	}
+type1:
+#endif /* CONFIG_PCI_EXPRESS */
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
 	region = request_region(0xCF8, 8, "PCI conf1");
diff -Naur linux-2.6.0/arch/i386/pci/Makefile
linux_pciexpress/arch/i386/pci/Makefile
--- linux-2.6.0/arch/i386/pci/Makefile	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/Makefile	2004-01-29
16:14:45.000000000 +0530
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_PCI_EXPRESS)	+= direct.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI_PCI)		+= acpi.o
diff -Naur linux-2.6.0/arch/i386/pci/pci.h
linux_pciexpress/arch/i386/pci/pci.h
--- linux-2.6.0/arch/i386/pci/pci.h	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/pci.h	2004-01-29
16:14:45.000000000 +0530
@@ -15,6 +15,11 @@
 #define PCI_PROBE_BIOS		0x0001
 #define PCI_PROBE_CONF1		0x0002
 #define PCI_PROBE_CONF2		0x0004
+#ifdef CONFIG_PCI_EXPRESS
+#define PCI_PROBE_ENHANCED	0x0008
+#else
+#define PCI_PROBE_ENHANCED 	0x0
+#endif
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_NO_CHECKS		0x0400
diff -Naur linux-2.6.0/drivers/acpi/tables.c
linux_pciexpress/drivers/acpi/tables.c
--- linux-2.6.0/drivers/acpi/tables.c	2003-12-18 08:28:46.000000000
+0530
+++ linux_pciexpress/drivers/acpi/tables.c	2004-01-29
16:14:08.000000000 +0530
@@ -58,6 +58,7 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 /* System Description Table (RSDT/XSDT) */
diff -Naur linux-2.6.0/drivers/pci/pci.c
linux_pciexpress/drivers/pci/pci.c
--- linux-2.6.0/drivers/pci/pci.c	2003-12-18 08:28:38.000000000
+0530
+++ linux_pciexpress/drivers/pci/pci.c	2004-01-29 16:13:58.000000000
+0530
@@ -90,6 +90,7 @@
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
  *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI-EXP
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
diff -Naur linux-2.6.0/drivers/pci/probe.c
linux_pciexpress/drivers/pci/probe.c
--- linux-2.6.0/drivers/pci/probe.c	2003-12-18 08:29:06.000000000
+0530
+++ linux_pciexpress/drivers/pci/probe.c	2004-01-29
16:13:58.000000000 +0530
@@ -17,6 +17,8 @@
 
 #define CARDBUS_LATENCY_TIMER	176	/* secondary latency timer */
 #define CARDBUS_RESERVE_BUSNR	3
+#define PCI_CFG_SPACE_SIZE	256
+#define PCI_CFG_SPACE_EXP_SIZE	4096
 
 /* Ugh.  Need to stop exporting this to modules. */
 LIST_HEAD(pci_root_buses);
@@ -479,6 +481,21 @@
 	kfree(pci_dev);
 }
 
+/* 
+ * pci_cfg_space_size - get the configuration space size of the PCI
device
+ */
+static int pci_cfg_space_size(struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI_EXPRESS
+	/* Find whether the device is PCI Express device */
+	int is_pci_express_dev = 
+		pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (is_pci_express_dev)
+		return PCI_CFG_SPACE_EXP_SIZE;
+#endif
+	return PCI_CFG_SPACE_SIZE; 
+}
+
 /*
  * Read the config data for a PCI device, sanity-check it
  * and fill in the dev structure...
@@ -515,6 +532,7 @@
 	dev->multifunction = !!(hdr_type & 0x80);
 	dev->vendor = l & 0xffff;
 	dev->device = (l >> 16) & 0xffff;
+	dev->cfg_size = pci_cfg_space_size(dev);
 
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
diff -Naur linux-2.6.0/drivers/pci/proc.c
linux_pciexpress/drivers/pci/proc.c
--- linux-2.6.0/drivers/pci/proc.c	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/drivers/pci/proc.c	2004-01-29 16:13:58.000000000
+0530
@@ -16,14 +16,15 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 
-#define PCI_CFG_SPACE_SIZE 256
-
 static int proc_initialized;	/* = 0 */
 
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
 	loff_t new = -1;
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
 
 	lock_kernel();
 	switch (whence) {
@@ -34,11 +35,11 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
-		new = PCI_CFG_SPACE_SIZE + off;
+		new = dev->cfg_size + off;
 		break;
 	}
 	unlock_kernel();
-	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
+	if (new < 0 || new > dev->cfg_size)
 		return -EINVAL;
 	return (file->f_pos = new);
 }
@@ -59,7 +60,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+ 		size = dev->cfg_size;
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -133,13 +134,14 @@
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
 	int cnt;
+	int size = dev->cfg_size;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -401,7 +403,7 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+	e->size = dev->cfg_size;
 
 	return 0;
 }
diff -Naur linux-2.6.0/include/asm-i386/fixmap.h
linux_pciexpress/include/asm-i386/fixmap.h
--- linux-2.6.0/include/asm-i386/fixmap.h	2003-12-18
08:28:06.000000000 +0530
+++ linux_pciexpress/include/asm-i386/fixmap.h	2004-01-29
16:15:38.000000000 +0530
@@ -67,6 +67,9 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings
*/
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	FIX_PCIE_MCFG,
+#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
diff -Naur linux-2.6.0/include/asm-i386/pci.h
linux_pciexpress/include/asm-i386/pci.h
--- linux-2.6.0/include/asm-i386/pci.h	2003-12-18 08:28:47.000000000
+0530
+++ linux_pciexpress/include/asm-i386/pci.h	2004-01-29
16:15:39.000000000 +0530
@@ -96,4 +96,69 @@
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
+#ifdef CONFIG_PCI_EXPRESS
+extern spinlock_t pci_config_lock;
+
+/*
+ * Variable used to store the base address of the last PCI Express
device
+ * accessed.
+ */
+extern u32 pcie_last_accessed_device;
+
+/*
+ * Variable used to store the base address of the chipset
+ */
+extern u32 mmcfg_base_address;
+
+/*
+ * Variable used to store the virtual  address of fixed PTE
+ */
+extern char *mmcfg_virt_addr;
+
+static inline void pci_exp_set_dev_base(int bus, int devfn)
+{
+	u32 dev_base = 
+		mmcfg_base_address | (bus << 20) | (devfn << 12);
+	if (dev_base != pcie_last_accessed_device) {
+		pcie_last_accessed_device = dev_base;
+		set_fixmap(FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static inline void pci_express_read(int bus, int devfn, int reg, 
+		int len, u32 *value)
+{
+	pci_exp_set_dev_base(bus, devfn);
+ 	switch (len) {
+        case 1:
+		*value = (u8)readb(mmcfg_virt_addr + reg);
+		break;
+        case 2:
+		*value = (u16)readw(mmcfg_virt_addr + reg);
+		break;
+        case 4:
+		*value = (u32)readl(mmcfg_virt_addr + reg);
+		break;
+	}
+}
+
+static inline void pci_express_write(int bus, int devfn, int reg, 
+	int len, u32 value)
+{
+	pci_exp_set_dev_base(bus, devfn);
+	switch (len) {
+		case 1:
+			writeb(value, mmcfg_virt_addr + reg);
+			break;
+		case 2:
+			writew(value, mmcfg_virt_addr + reg);
+			break;
+	        case 4:
+			writel(value, mmcfg_virt_addr + reg);
+	                break;
+     	}
+	/* Dummy read to flush PCI write */
+	readl(mmcfg_virt_addr);
+}
+#endif /* CONFIG_PCI_EXPRESS */
 #endif /* __i386_PCI_H */
diff -Naur linux-2.6.0/include/linux/acpi.h
linux_pciexpress/include/linux/acpi.h
--- linux-2.6.0/include/linux/acpi.h	2003-12-18 08:27:58.000000000
+0530
+++ linux_pciexpress/include/linux/acpi.h	2004-01-29
16:15:20.000000000 +0530
@@ -317,6 +317,13 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+struct acpi_table_mcfg {
+	struct acpi_table_header 	header;
+	u8	reserved[8];
+	u32	base_address;
+	u32	base_reserved;
+} __attribute__ ((packed));
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +345,7 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
@@ -437,4 +445,7 @@
 
 #endif /*!CONFIG_ACPI_INTERPRETER*/
 
+#ifdef CONFIG_PCI_EXPRESS
+extern u32 mmcfg_base_address;
+#endif
 #endif /*_LINUX_ACPI_H*/
diff -Naur linux-2.6.0/include/linux/pci.h
linux_pciexpress/include/linux/pci.h
--- linux-2.6.0/include/linux/pci.h	2003-12-18 08:28:49.000000000
+0530
+++ linux_pciexpress/include/linux/pci.h	2004-01-29
16:43:01.000000000 +0530
@@ -198,6 +198,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled
Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI-EXPANDED */
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list
*/
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16
bits) */
 #define PCI_CAP_SIZEOF		4
@@ -424,6 +425,7 @@
 #define PCI_NAME_HALF	__stringify(20)	/* less than half to handle slop
*/
 	char		pretty_name[PCI_NAME_SIZE];	/* pretty name
for users to see */
 #endif
+	int cfg_size;
 };
 
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)

^ permalink raw reply	[flat|nested] 43+ messages in thread
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-22 10:21 Durairaj, Sundarapandian
  2004-01-22 10:44 ` Andrew Morton
                   ` (4 more replies)
  0 siblings, 5 replies; 43+ messages in thread
From: Durairaj, Sundarapandian @ 2004-01-22 10:21 UTC (permalink / raw)
  To: linux-kernel, linux-pci
  Cc: torvalds, alan, greg, Andi Kleen, Kondratiev, Vladimir, Seshadri,
	Harinarayanan, Durairaj, Sundarapandian

Hi All, 

I am reposting the updated patch after incorporating the review
comments.

This is the patch on PCI Express Enhanced configuration for 2.6.0 test11
kernel following up to the Vladimir (Vladimir.Kondratiev@intel.com) and
Harinarayanan (Harinarayanan.Seshadri@intel.com)  and my previous
patches .
I tested it on our i386 platform. 

This patch also implements a mechanism for the kernel to find the
chipset specific mmcfg base address. The kernel will detect the base
address of the chipset through the ACPI table entry and based on that
the PCI subsystem will be initialized.  

Please review this and send in your comments.

Thanks,
Sundar

diff -Naur linux-2.6.0/arch/i386/Kconfig
linux_pciexpress/arch/i386/Kconfig
--- linux-2.6.0/arch/i386/Kconfig	2003-12-18 08:28:16.000000000
+0530
+++ linux_pciexpress/arch/i386/Kconfig	2004-01-12 14:28:38.000000000
+0530
@@ -959,7 +959,7 @@
 endmenu
 
 
-menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA, PCI_EXPRESS)"
 
 config X86_VISWS_APIC
 	bool
@@ -976,6 +976,18 @@
 	depends on SMP && !(X86_VISWS || X86_VOYAGER)
 	default y
 
+config PCI_EXPRESS
+	bool "PCI_EXPRESS (EXPERIMENTAL)" 
+	depends on EXPERIMENTAL && ACPI_BOOT
+	help
+	  PCI Express extends the configuration space from 256 bytes to
+	  4k bytes. It also defines an enhanced configuration mechanism
+	  to acces the extended configuration space.
+	  With this option, you can specify that Linux will first
attempt
+	  to access the pci configuration space through enhanced config
+	  access mechanism (Will work only on PCI Express based system)
+	  otherwise the pci direct mechanism will be used.
+
 config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
diff -Naur linux-2.6.0/arch/i386/kernel/acpi/boot.c
linux_pciexpress/arch/i386/kernel/acpi/boot.c
--- linux-2.6.0/arch/i386/kernel/acpi/boot.c	2003-12-18
08:29:29.000000000 +0530
+++ linux_pciexpress/arch/i386/kernel/acpi/boot.c	2004-01-12
14:14:22.000000000 +0530
@@ -93,6 +93,29 @@
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_PCI_EXPRESS
+extern u32 mmcfg_base_address;
+static int __init acpi_parse_mcfg
+			 (unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg	*mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table
+						(phys_addr, size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+	if (mcfg->base_address)
+		mmcfg_base_address = (u32)mcfg->base_address;
+	printk(KERN_INFO PREFIX "Local  mcfg address %p\n",
+			mcfg->base_address);
+	return 0;
+}
+#endif /* CONFIG_PCI_EXPRESS*/
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -508,6 +531,22 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
+#ifdef CONFIG_PCI_EXPRESS
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MCFG not present\n");
+		return 0;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
+		return result;
+	}
+	else if (result > 1) {
+		printk(KERN_WARNING PREFIX \
+			"Multiple MCFG tables exist\n");
+	}
+#endif /*CONFIG_PCI_EXPRESS*/
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
diff -Naur linux-2.6.0/arch/i386/pci/common.c
linux_pciexpress/arch/i386/pci/common.c
--- linux-2.6.0/arch/i386/pci/common.c	2003-12-18 08:28:46.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/common.c	2004-01-22
11:54:42.000000000 +0530
@@ -19,7 +19,8 @@
 extern  void pcibios_sort(void);
 #endif
 
-unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 |
PCI_PROBE_CONF2;
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 |
PCI_PROBE_CONF2
+				 | PCI_PROBE_ENHANCED;
 
 int pcibios_last_bus = -1;
 struct pci_bus *pci_root_bus = NULL;
@@ -197,6 +198,12 @@
 		return NULL;
 	}
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	else if (!strcmp(str, "no_pcie")) {
+		pci_probe &= !PCI_PROBE_ENHANCED;
+		return NULL;
+	}
+#endif
 #ifdef CONFIG_ACPI_PCI
 	else if (!strcmp(str, "noacpi")) {
 		pci_probe |= PCI_NO_ACPI_ROUTING;
diff -Naur linux-2.6.0/arch/i386/pci/direct.c
linux_pciexpress/arch/i386/pci/direct.c
--- linux-2.6.0/arch/i386/pci/direct.c	2003-12-18 08:28:28.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/direct.c	2004-01-22
12:07:37.000000000 +0530
@@ -168,6 +168,71 @@
 
 
 /*
+ *We map full Page size on each request. Incidently that's the size we
+ *have for config space too.
+ */
+#ifdef CONFIG_PCI_EXPRESS
+/* 
+ *On PCI Express capable platform, at the time of kernel initialization
+ *the os would have scanned for mcfg table and set this variable to 
+ *appropriate value. If PCI Express not supported the variable will 
+ * have 0 value
+ */
+u32 mmcfg_base_address;
+
+/*
+ *Variable used to store the virtual  address of fixed PTE
+ */
+char * mmcfg_virt_addr;
+
+static int pci_express_conf_read(int seg, int bus,
+		int devfn, int reg, int len, u32 *value)
+{
+	if (!value || ((u32)bus > 255) || ((u32)devfn > 255) 
+		|| ((u32)reg > 4095)){
+		printk(KERN_ERR "pci_express_conf_read: \
+					Invalid Parameter\n");
+  		return -EINVAL;
+	}
+
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1)){
+		printk(KERN_ERR "pci_express_conf_read: \
+					misalligned transaction\n");
+  		return -EINVAL;
+	}
+	pci_express_read(bus, devfn, reg, len, value);
+
+	return 0;
+}
+ 
+static int pci_express_conf_write(int seg, int bus, 
+			int devfn, int reg, int len, u32 value)
+{
+	if (((u32)bus > 255) || ((u32)devfn > 255) 
+		|| ((u32)reg > 4095)){
+		printk(KERN_ERR "pci_express_conf_write: \
+					Invalid Parameter\n");
+		return -EINVAL;
+	}
+
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1)){
+		printk(KERN_ERR "pci_express_conf_write: \
+					misalligned transaction\n");
+  		return -EINVAL;
+	}
+	pci_express_write(bus, devfn, reg, len, value);
+	return 0;
+}
+
+static struct pci_raw_ops pci_express_conf = {
+	.read   =	pci_express_conf_read,
+	.write  =	pci_express_conf_write,
+};
+#endif /* CONFIG_PCI_EXPRESS */
+
+/*
  * Before we decide to use direct hardware access mechanisms, we try to
do some
  * trivial checks to ensure it at least _seems_ to be working -- we
just test
  * whether bus 00 contains a host bridge (this is similar to checking
@@ -244,7 +309,31 @@
 static int __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
+	
+#ifdef CONFIG_PCI_EXPRESS
+	if ((pci_probe & PCI_PROBE_ENHANCED) == 0)
+		goto type1;
+	/*
+ 	 *Check if platform we are running is pci express capable
+  	 */
+	if (mmcfg_base_address == 0){
+		printk(KERN_INFO 
+		      "MCFG table entry is not found in ACPI
tables....\n \
+		       PCI Express not supported in this platform....\n
\
+		       Not enabling Enhanced Configuration....\n");
+		goto type1;
+	}
 
+	/* Calculate the virtual address of the PTE */
+	mmcfg_virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
+
+	if (pci_sanity_check(&pci_express_conf)) {
+		printk(KERN_INFO "PCI:Using config type PCIExp\n");
+		raw_pci_ops = &pci_express_conf;
+		return 0;
+	}
+type1:
+#endif /* CONFIG_PCI_EXPRESS */
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
 	region = request_region(0xCF8, 8, "PCI conf1");
diff -Naur linux-2.6.0/arch/i386/pci/Makefile
linux_pciexpress/arch/i386/pci/Makefile
--- linux-2.6.0/arch/i386/pci/Makefile	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/Makefile	2004-01-12
13:38:55.000000000 +0530
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_PCI_EXPRES)	+= direct.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI_PCI)		+= acpi.o
diff -Naur linux-2.6.0/arch/i386/pci/pci.h
linux_pciexpress/arch/i386/pci/pci.h
--- linux-2.6.0/arch/i386/pci/pci.h	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/pci.h	2004-01-12
13:38:55.000000000 +0530
@@ -15,6 +15,11 @@
 #define PCI_PROBE_BIOS		0x0001
 #define PCI_PROBE_CONF1		0x0002
 #define PCI_PROBE_CONF2		0x0004
+#ifdef CONFIG_PCI_EXPRESS
+#define PCI_PROBE_ENHANCED	0x0008
+#else
+#define PCI_PROBE_ENHANCED 	0x0
+#endif
 #define PCI_NO_SORT		0x0100
 #define PCI_BIOS_SORT		0x0200
 #define PCI_NO_CHECKS		0x0400
diff -Naur linux-2.6.0/drivers/acpi/tables.c
linux_pciexpress/drivers/acpi/tables.c
--- linux-2.6.0/drivers/acpi/tables.c	2003-12-18 08:28:46.000000000
+0530
+++ linux_pciexpress/drivers/acpi/tables.c	2004-01-12
13:38:20.000000000 +0530
@@ -58,6 +58,7 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 /* System Description Table (RSDT/XSDT) */
diff -Naur linux-2.6.0/drivers/pci/pci.c
linux_pciexpress/drivers/pci/pci.c
--- linux-2.6.0/drivers/pci/pci.c	2003-12-18 08:28:38.000000000
+0530
+++ linux_pciexpress/drivers/pci/pci.c	2004-01-12 13:38:06.000000000
+0530
@@ -90,6 +90,8 @@
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
  *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI-EXP
+
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
diff -Naur linux-2.6.0/drivers/pci/proc.c
linux_pciexpress/drivers/pci/proc.c
--- linux-2.6.0/drivers/pci/proc.c	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/drivers/pci/proc.c	2004-01-12 14:36:27.000000000
+0530
@@ -17,13 +17,30 @@
 #include <asm/byteorder.h>
 
 #define PCI_CFG_SPACE_SIZE 256
+#define PCI_CFG_SPACE_EXP_SIZE 4096
 
 static int proc_initialized;	/* = 0 */
 
+static int pci_cfg_space_size (struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI_EXPRESS
+	/* Find whether the device is PCI Express device */
+	int is_pci_express_dev = 
+		pci_find_capability(dev, PCI_CAP_ID_EXP);
+	if (is_pci_express_dev)
+		return PCI_CFG_SPACE_EXP_SIZE;
+	else
+#endif
+	return PCI_CFG_SPACE_SIZE; 
+}
+
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
 	loff_t new = -1;
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
 
 	lock_kernel();
 	switch (whence) {
@@ -34,11 +51,11 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
-		new = PCI_CFG_SPACE_SIZE + off;
+		new = pci_cfg_space_size(dev) + off;
 		break;
 	}
 	unlock_kernel();
-	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
+	if (new < 0 || new > pci_cfg_space_size(dev))
 		return -EINVAL;
 	return (file->f_pos = new);
 }
@@ -59,7 +76,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+ 		size = pci_cfg_space_size (dev);
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -134,12 +151,14 @@
 	int pos = *ppos;
 	int cnt;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	int size;
+	size = pci_cfg_space_size(dev);
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -384,6 +403,7 @@
 	struct pci_bus *bus = dev->bus;
 	struct proc_dir_entry *de, *e;
 	char name[16];
+	int size;
 
 	if (!proc_initialized)
 		return -EACCES;
@@ -401,7 +421,8 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+	size = pci_cfg_space_size(dev);
+	e->size = size;
 
 	return 0;
 }
diff -Naur linux-2.6.0/include/asm-i386/fixmap.h
linux_pciexpress/include/asm-i386/fixmap.h
--- linux-2.6.0/include/asm-i386/fixmap.h	2003-12-18
08:28:06.000000000 +0530
+++ linux_pciexpress/include/asm-i386/fixmap.h	2004-01-12
13:40:19.000000000 +0530
@@ -67,6 +67,9 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings
*/
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef CONFIG_PCI_EXPRESS
+	FIX_PCIE_MCFG,
+#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
diff -Naur linux-2.6.0/include/asm-i386/pci.h
linux_pciexpress/include/asm-i386/pci.h
--- linux-2.6.0/include/asm-i386/pci.h	2003-12-18 08:28:47.000000000
+0530
+++ linux_pciexpress/include/asm-i386/pci.h	2004-01-12
14:39:42.000000000 +0530
@@ -96,4 +96,68 @@
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
+#ifdef CONFIG_PCI_EXPRESS
+/*
+ *Variable used to store the base address of the last pciexpress device
+ *accessed.
+ */
+static u32 pcie_last_accessed_device;
+
+extern u32 mmcfg_base_address;
+extern spinlock_t pci_config_lock;
+extern char * mmcfg_virt_addr;
+
+static __inline__ void pci_exp_set_dev_base (int bus, int devfn)
+{
+	u32 dev_base = 
+		mmcfg_base_address | (bus << 20) | (devfn << 12);
+	if (dev_base != pcie_last_accessed_device){
+		pcie_last_accessed_device = dev_base;
+		set_fixmap (FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static __inline__ void pci_express_read(int bus, int devfn, int reg, 
+		int len, u32 *value)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, devfn);
+ 	switch (len) {
+        case 1:
+		*value = (u8)readb((unsigned long) mmcfg_virt_addr +
reg);
+		break;
+        case 2:
+		*value = (u16)readw((unsigned long) mmcfg_virt_addr +
reg);
+		break;
+        case 4:
+		*value = (u32)readl((unsigned long) mmcfg_virt_addr +
reg);
+		break;
+	}
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+
+static __inline__ void pci_express_write(int bus, int devfn, int reg, 
+	int len, u32 value)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, devfn);
+	switch (len) {
+		case 1:
+			writeb(value,(unsigned long)mmcfg_virt_addr +
reg);
+			break;
+		case 2:
+			writew(value,(unsigned long)mmcfg_virt_addr +
reg);
+			break;
+	        case 4:
+			writel(value,(unsigned long)mmcfg_virt_addr +
reg);
+	                break;
+     	}
+	/* Dummy read to flush PCI write */
+	readl (mmcfg_virt_addr);
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+#endif /* CONFIG_PCI_EXPRESS */
 #endif /* __i386_PCI_H */
diff -Naur linux-2.6.0/include/linux/acpi.h
linux_pciexpress/include/linux/acpi.h
--- linux-2.6.0/include/linux/acpi.h	2003-12-18 08:27:58.000000000
+0530
+++ linux_pciexpress/include/linux/acpi.h	2004-01-12
14:43:23.000000000 +0530
@@ -317,6 +317,12 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+struct acpi_table_mcfg {
+	struct acpi_table_header 	header;
+	u8	reserved[8];
+	u64	base_address;
+} __attribute__ ((packed));
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +344,7 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
diff -Naur linux-2.6.0/include/linux/pci.h
linux_pciexpress/include/linux/pci.h
--- linux-2.6.0/include/linux/pci.h	2003-12-18 08:28:49.000000000
+0530
+++ linux_pciexpress/include/linux/pci.h	2004-01-12
13:40:01.000000000 +0530
@@ -198,6 +198,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled
Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI-Express*/
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list
*/
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16
bits) */
 #define PCI_CAP_SIZEOF		4

^ permalink raw reply	[flat|nested] 43+ messages in thread
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-07 16:44 Nakajima, Jun
  0 siblings, 0 replies; 43+ messages in thread
From: Nakajima, Jun @ 2004-01-07 16:44 UTC (permalink / raw)
  To: Durairaj, Sundarapandian, linux-kernel
  Cc: Grege, Seshadri, Harinarayanan, Kondratiev, Vladimir, Brown, Len

This was pointed out before, but you have dependency on ACPI (i.e.
CONFIG_ACPI_BOOT). To me, it's not resolved yet in this patch.

>  static int __init pci_direct_init(void)
>  {
>  	struct resource *region, *region2;
> +	unsigned long flags;
> +#ifdef CONFIG_PCI_EXP_ENHANCED

I think you should move flags inside #ifdef. But do you really need to
hold a spin lock there? This is done by arch_initcall().

	Jun
> -----Original Message-----
> From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-
> owner@vger.kernel.org] On Behalf Of Durairaj, Sundarapandian
> Sent: Wednesday, January 07, 2004 5:00 AM
> To: linux-kernel@vger.kernel.org
> Cc: Grege@kroah.com; Seshadri, Harinarayanan; Kondratiev, Vladimir
> Subject: RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
> 
> Hi All,
> 
> Thanks for your review comments. I am reposting the updated patch
after
> incorporating the review comments.
> Please review this and send your comments.
> 
> Thanks,
> Sundar
> 
> ------------------------------------------------
> 
> diff -Naur linux-2.6.0/arch/i386/Kconfig
> linux_pciexpress/arch/i386/Kconfig
> --- linux-2.6.0/arch/i386/Kconfig	2003-12-18 08:28:16.000000000
> +0530
> +++ linux_pciexpress/arch/i386/Kconfig	2004-01-07
10:59:23.000000000
> +0530
> @@ -959,7 +959,7 @@
>  endmenu
> 
> 
> -menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
> +menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA, PCI_EXPRESS)"
> 
>  config X86_VISWS_APIC
>  	bool
> @@ -976,6 +976,18 @@
>  	depends on SMP && !(X86_VISWS || X86_VOYAGER)
>  	default y
> 
> +config PCI_EXP_ENHANCED
> +	bool "PCI_EXPRESS (EXPERIMENTAL)"
> +	depends on EXPERIMENTAL
> +	help
> +	   PCI Express extends the configuration space from 256 bytes to
> 4k
> +	   bytes. It also defines an enhanced configuration mechanism to
> acces
> +	   the extended configuration space.
> +	   With this option, you can specify that Linux will first
> attempt to
> +	   access the pci configuration space through enhanced config
> access
> +	   mechanism (Will work only on PCI Express based system)
> otherwise the
> +	   pci direct mechanism will be used.
> +
>  config PCI
>  	bool "PCI support" if !X86_VISWS
>  	depends on !X86_VOYAGER
> diff -Naur linux-2.6.0/arch/i386/kernel/acpi/boot.c
> linux_pciexpress/arch/i386/kernel/acpi/boot.c
> --- linux-2.6.0/arch/i386/kernel/acpi/boot.c	2003-12-18
> 08:29:29.000000000 +0530
> +++ linux_pciexpress/arch/i386/kernel/acpi/boot.c	2004-01-07
> 18:20:23.000000000 +0530
> @@ -93,6 +93,28 @@
>  	return ((unsigned char *) base + offset);
>  }
> 
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +extern u64 mmcfg_base_address;
> +static int __init acpi_parse_mcfg
> +			 (unsigned long phys_addr, unsigned long size)
> +{
> +	struct acpi_table_mcfg	*mcfg = NULL;
> +
> +	if (!phys_addr || !size)
> +		return -EINVAL;
> +
> +	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr,
> size);
> +	if (!mcfg) {
> +		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
> +		return -ENODEV;
> +	}
> +	if (mcfg->base_address)
> +		mmcfg_base_address =mcfg->base_address;
> +	printk(KERN_INFO PREFIX "Local  mcfg address %p\n",
> +			mcfg->base_address);
> +	return 0;
> +}
> +#endif /* CONFIG_PCI_EXP_ENHANCED*/
> 
>  #ifdef CONFIG_X86_LOCAL_APIC
> 
> @@ -508,6 +530,21 @@
> 
>  #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
> 
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
> +	if (!result) {
> +		printk(KERN_WARNING PREFIX "MCFG not present\n");
> +		return 0;
> +	}
> +	else if (result < 0) {
> +		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
> +		return result;
> +	}
> +	else if (result > 1) {
> +		printk(KERN_WARNING PREFIX "Multiple MCFG tables
> exist\n");
> +	}
> +#endif /*CONFIG_PCI_EXP_ENHANCED*/
> +
>  #ifdef CONFIG_X86_LOCAL_APIC
>  	if (acpi_lapic && acpi_ioapic) {
>  		smp_found_config = 1;
> diff -Naur linux-2.6.0/arch/i386/pci/direct.c
> linux_pciexpress/arch/i386/pci/direct.c
> --- linux-2.6.0/arch/i386/pci/direct.c	2003-12-18
08:28:28.000000000
> +0530
> +++ linux_pciexpress/arch/i386/pci/direct.c	2004-01-07
> 18:16:57.000000000 +0530
> @@ -168,6 +168,124 @@
> 
> 
>  /*
> + *We map full Page size on each request. Incidently that's the size
we
> + *have for config space too.
> + */
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +/*
> + *On PCI Express capable platform, at the time of kernel
initialization
> + *the os would have scanned for mcfg table and set this variable to
> + *appropriate value.
> + *If PCI Express not supported the variable will have 0 value
> + */
> +u64 mmcfg_base_address;
> +
> +/*
> + *Variable used to store the base address of the last pciexpress
device
> 
> + *accessed.
> + */
> +u32 pcie_last_accessed_device;
> +
> +unsigned long pci_exp_set_dev_base (int bus, int dev, int fn)
> +{
> +	u32 dev_base =
> +		mmcfg_base_address | (bus << 20) | ((PCI_DEVFN (dev,fn))
> <<12);
> +	if (dev_base != pcie_last_accessed_device){
> +		pcie_last_accessed_device = dev_base;
> +		set_fixmap (FIX_PCIE_MCFG, dev_base);
> +	}
> +	return 0;
> +}
> +
> +static int pci_express_conf_read(int seg, int bus,
> +		int devfn, int reg, int len, u32 *value)
> +{
> +	unsigned long flags;
> +	char * virt_addr;
> +	int dev = PCI_SLOT (devfn);
> +	int fn  = PCI_FUNC (devfn);
> +
> +	if (!value || ((u32)bus > 255) || ((u32)dev > 31)
> +			|| ((u32)fn > 7) || ((u32)reg > 4095)){
> +		printk(KERN_ERR "pci_express_conf_read: Invalid
> Parameter\n");
> +  		return -EINVAL;
> +	}
> +
> +	/* Shoot misalligned transaction now */
> +	if (reg & (len-1)){
> +		printk(KERN_ERR "pci_express_conf_read: \
> +					misalligned transaction\n");
> +  		return -EINVAL;
> +	}
> +
> +	spin_lock_irqsave(&pci_config_lock, flags);
> +	pci_exp_set_dev_base(bus, dev, fn);
> +	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
> + 	switch (len) {
> +        case 1:
> +		*value = (u8)readb((unsigned long) virt_addr+reg);
> +		break;
> +        case 2:
> +		*value = (u16)readw((unsigned long) virt_addr+reg);
> +		break;
> +        case 4:
> +		*value = (u32)readl((unsigned long) virt_addr+reg);
> +		break;
> +	}
> +	spin_unlock_irqrestore(&pci_config_lock, flags);
> +	return 0;
> +}
> +
> +static int pci_express_conf_write(int seg, int bus,
> +			int devfn, int reg, int len, u32 value)
> +{
> +	unsigned long flags;
> +	unsigned char * virt_addr;
> +	int dev = PCI_SLOT (devfn);
> +	int fn  = PCI_FUNC (devfn);
> +
> +	if (!value || ((u32)bus > 255) || ((u32)dev > 31) ||
> +		((u32)fn > 7) || ((u32)reg > 4095)){
> +		printk(KERN_ERR "pci_express_conf_write: \
> +					Invalid Parameter\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Shoot misalligned transaction now */
> +	if (reg & (len-1)){
> +		printk(KERN_ERR "pci_express_conf_write: \
> +					misalligned transaction\n");
> +  		return -EINVAL;
> +	}
> +
> +	spin_lock_irqsave(&pci_config_lock, flags);
> +	pci_exp_set_dev_base(bus, dev, fn);
> +	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
> +
> +	switch (len) {
> +		case 1:
> +			writeb(value,(unsigned long)virt_addr+reg);
> +			break;
> +		case 2:
> +			writew(value,(unsigned long)virt_addr+reg);
> +			break;
> +	        case 4:
> +			writel(value,(unsigned long)virt_addr+reg);
> +	                break;
> +     	}
> +	/* Dummy read to flush PCI write */
> +	readl (virt_addr);
> +	spin_unlock_irqrestore(&pci_config_lock, flags);
> +	return 0;
> +}
> +
> +static struct pci_raw_ops pci_express_conf = {
> +	.read   =	pci_express_conf_read,
> +	.write  =	pci_express_conf_write,
> +};
> +#endif /* CONFIG_PCI_EXP_ENHANCED */
> +
> +/*
>   * Before we decide to use direct hardware access mechanisms, we try
to
> do some
>   * trivial checks to ensure it at least _seems_ to be working -- we
> just test
>   * whether bus 00 contains a host bridge (this is similar to checking
> @@ -244,6 +362,28 @@
>  static int __init pci_direct_init(void)
>  {
>  	struct resource *region, *region2;
> +	unsigned long flags;
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +	/*
> + 	 *Check if platform we are running is pci express capable
> +  	 */
> +	if (mmcfg_base_address == 0){
> +		printk(KERN_INFO
> +			"MCFG table entry is not found in ACPI
> tables....\n \
> +			PCI Express not supported in this platform....\n
> \
> +			Not enabling Enhanced Configuration....\n");
> +	}
> +	else {
> +		local_irq_save(flags);
> +		if (pci_sanity_check(&pci_express_conf)) {
> +			local_irq_restore(flags);
> +			printk(KERN_INFO "PCI:Using config type
> PCIExp\n");
> +			raw_pci_ops = &pci_express_conf;
> +			return 0;
> +		}
> +		local_irq_restore(flags);
> +	}
> +#endif /* CONFIG_PCI_EXP_ENHANCED */
> 
>  	if ((pci_probe & PCI_PROBE_CONF1) == 0)
>  		goto type2;
> diff -Naur linux-2.6.0/arch/i386/pci/Makefile
> linux_pciexpress/arch/i386/pci/Makefile
> --- linux-2.6.0/arch/i386/pci/Makefile	2003-12-18
08:28:57.000000000
> +0530
> +++ linux_pciexpress/arch/i386/pci/Makefile	2004-01-07
> 10:59:23.000000000 +0530
> @@ -2,6 +2,7 @@
> 
>  obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
>  obj-$(CONFIG_PCI_DIRECT)	+= direct.o
> +obj-$(CONFIG_PCI_EXP_ENHANCED)	+= direct.o
> 
>  pci-y				:= fixup.o
>  pci-$(CONFIG_ACPI_PCI)		+= acpi.o
> diff -Naur linux-2.6.0/drivers/acpi/tables.c
> linux_pciexpress/drivers/acpi/tables.c
> --- linux-2.6.0/drivers/acpi/tables.c	2003-12-18 08:28:46.000000000
> +0530
> +++ linux_pciexpress/drivers/acpi/tables.c	2004-01-07
> 11:03:43.000000000 +0530
> @@ -58,6 +58,7 @@
>  	[ACPI_SSDT]		= "SSDT",
>  	[ACPI_SPMI]		= "SPMI",
>  	[ACPI_HPET]		= "HPET",
> +	[ACPI_MCFG]		= "MCFG",
>  };
> 
>  /* System Description Table (RSDT/XSDT) */
> diff -Naur linux-2.6.0/drivers/pci/pci.c
> linux_pciexpress/drivers/pci/pci.c
> --- linux-2.6.0/drivers/pci/pci.c	2003-12-18 08:28:38.000000000
> +0530
> +++ linux_pciexpress/drivers/pci/pci.c	2004-01-07
10:59:23.000000000
> +0530
> @@ -90,6 +90,8 @@
>   *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap
>   *
>   *  %PCI_CAP_ID_PCIX         PCI-X
> + *  %PCI_CAP_ID_EXP          PCI-EXP
> +
>   */
>  int
>  pci_find_capability(struct pci_dev *dev, int cap)
> diff -Naur linux-2.6.0/drivers/pci/proc.c
> linux_pciexpress/drivers/pci/proc.c
> --- linux-2.6.0/drivers/pci/proc.c	2003-12-18 08:28:57.000000000
> +0530
> +++ linux_pciexpress/drivers/pci/proc.c	2004-01-07
17:37:04.000000000
> +0530
> @@ -17,13 +17,29 @@
>  #include <asm/byteorder.h>
> 
>  #define PCI_CFG_SPACE_SIZE 256
> +#define PCI_CFG_SPACE_EXP_SIZE 4096
> 
>  static int proc_initialized;	/* = 0 */
> 
> +static int pci_cfg_space_size (struct pci_dev *dev)
> +{
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +	/* Find whether the device is PCI Express device */
> +	int is_pci_express_dev =  pci_find_capability(dev,
> PCI_CAP_ID_EXP);
> +	if (is_pci_express_dev)
> +		return PCI_CFG_SPACE_EXP_SIZE;
> +	else
> +#endif
> +	return PCI_CFG_SPACE_SIZE;
> +}
> +
>  static loff_t
>  proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
>  {
>  	loff_t new = -1;
> +	const struct inode *ino = file->f_dentry->d_inode;
> +	const struct proc_dir_entry *dp = PDE(ino);
> +	struct pci_dev *dev = dp->data;
> 
>  	lock_kernel();
>  	switch (whence) {
> @@ -34,11 +50,11 @@
>  		new = file->f_pos + off;
>  		break;
>  	case 2:
> -		new = PCI_CFG_SPACE_SIZE + off;
> +		new = pci_cfg_space_size(dev) + off;
>  		break;
>  	}
>  	unlock_kernel();
> -	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
> +	if (new < 0 || new > pci_cfg_space_size(dev))
>  		return -EINVAL;
>  	return (file->f_pos = new);
>  }
> @@ -59,7 +75,7 @@
>  	 */
> 
>  	if (capable(CAP_SYS_ADMIN))
> -		size = PCI_CFG_SPACE_SIZE;
> + 		size = pci_cfg_space_size (dev);
>  	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
>  		size = 128;
>  	else
> @@ -134,12 +150,14 @@
>  	int pos = *ppos;
>  	int cnt;
> 
> -	if (pos >= PCI_CFG_SPACE_SIZE)
> +	int size;
> +	size = pci_cfg_space_size(dev);
> +	if (pos >= size)
>  		return 0;
> -	if (nbytes >= PCI_CFG_SPACE_SIZE)
> -		nbytes = PCI_CFG_SPACE_SIZE;
> -	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
> -		nbytes = PCI_CFG_SPACE_SIZE - pos;
> +	if (nbytes >= size)
> +		nbytes = size;
> +	if (pos + nbytes > size)
> +		nbytes = size - pos;
>  	cnt = nbytes;
> 
>  	if (!access_ok(VERIFY_READ, buf, cnt))
> @@ -384,6 +402,7 @@
>  	struct pci_bus *bus = dev->bus;
>  	struct proc_dir_entry *de, *e;
>  	char name[16];
> +	int size;
> 
>  	if (!proc_initialized)
>  		return -EACCES;
> @@ -401,7 +420,9 @@
>  		return -ENOMEM;
>  	e->proc_fops = &proc_bus_pci_operations;
>  	e->data = dev;
> -	e->size = PCI_CFG_SPACE_SIZE;
> +
> +	size = pci_cfg_space_size(dev);
> +	e->size = size;
> 
>  	return 0;
>  }
> diff -Naur linux-2.6.0/include/asm-i386/fixmap.h
> linux_pciexpress/include/asm-i386/fixmap.h
> --- linux-2.6.0/include/asm-i386/fixmap.h	2003-12-18
> 08:28:06.000000000 +0530
> +++ linux_pciexpress/include/asm-i386/fixmap.h	2004-01-07
> 10:59:23.000000000 +0530
> @@ -67,6 +67,9 @@
>  	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings
> */
>  	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
>  #endif
> +#ifdef CONFIG_PCI_EXP_ENHANCED
> +	FIX_PCIE_MCFG,
> +#endif
>  #ifdef CONFIG_ACPI_BOOT
>  	FIX_ACPI_BEGIN,
>  	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
> diff -Naur linux-2.6.0/include/linux/acpi.h
> linux_pciexpress/include/linux/acpi.h
> --- linux-2.6.0/include/linux/acpi.h	2003-12-18 08:27:58.000000000
> +0530
> +++ linux_pciexpress/include/linux/acpi.h	2004-01-07
> 12:02:35.000000000 +0530
> @@ -317,6 +317,13 @@
>  	char				ec_id[0];
>  } __attribute__ ((packed));
> 
> +struct acpi_table_mcfg {
> +	struct acpi_table_header 	header;
> +	u8	reserved[8];
> +	u64	base_address;
> +} __attribute__ ((packed));
> +
> +
>  /* Table Handlers */
> 
>  enum acpi_table_id {
> @@ -338,6 +345,7 @@
>  	ACPI_SSDT,
>  	ACPI_SPMI,
>  	ACPI_HPET,
> +	ACPI_MCFG,
>  	ACPI_TABLE_COUNT
>  };
> 
> diff -Naur linux-2.6.0/include/linux/pci.h
> linux_pciexpress/include/linux/pci.h
> --- linux-2.6.0/include/linux/pci.h	2003-12-18 08:28:49.000000000
> +0530
> +++ linux_pciexpress/include/linux/pci.h	2004-01-07
> 10:59:23.000000000 +0530
> @@ -198,6 +198,7 @@
>  #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled
> Interrupts */
>  #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
>  #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
> +#define  PCI_CAP_ID_EXP 	0x10	/* PCI-Express*/
>  #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list
> */
>  #define PCI_CAP_FLAGS		2	/* Capability defined
flags (16
> bits) */
>  #define PCI_CAP_SIZEOF		4
> -
> To unsubscribe from this list: send the line "unsubscribe
linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 43+ messages in thread
* RE: [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2004-01-07 12:59 Durairaj, Sundarapandian
  2004-01-07 14:08 ` Meelis Roos
  2004-01-07 17:34 ` Vladimir Kondratiev
  0 siblings, 2 replies; 43+ messages in thread
From: Durairaj, Sundarapandian @ 2004-01-07 12:59 UTC (permalink / raw)
  To: linux-kernel; +Cc: Grege, Seshadri, Harinarayanan, Kondratiev, Vladimir

Hi All,

Thanks for your review comments. I am reposting the updated patch after
incorporating the review comments.
Please review this and send your comments.

Thanks,
Sundar

------------------------------------------------

diff -Naur linux-2.6.0/arch/i386/Kconfig
linux_pciexpress/arch/i386/Kconfig
--- linux-2.6.0/arch/i386/Kconfig	2003-12-18 08:28:16.000000000
+0530
+++ linux_pciexpress/arch/i386/Kconfig	2004-01-07 10:59:23.000000000
+0530
@@ -959,7 +959,7 @@
 endmenu
 
 
-menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA, PCI_EXPRESS)"
 
 config X86_VISWS_APIC
 	bool
@@ -976,6 +976,18 @@
 	depends on SMP && !(X86_VISWS || X86_VOYAGER)
 	default y
 
+config PCI_EXP_ENHANCED
+	bool "PCI_EXPRESS (EXPERIMENTAL)" 
+	depends on EXPERIMENTAL 
+	help
+	   PCI Express extends the configuration space from 256 bytes to
4k
+	   bytes. It also defines an enhanced configuration mechanism to
acces
+	   the extended configuration space.
+	   With this option, you can specify that Linux will first
attempt to
+	   access the pci configuration space through enhanced config
access
+	   mechanism (Will work only on PCI Express based system)
otherwise the
+	   pci direct mechanism will be used.
+
 config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
diff -Naur linux-2.6.0/arch/i386/kernel/acpi/boot.c
linux_pciexpress/arch/i386/kernel/acpi/boot.c
--- linux-2.6.0/arch/i386/kernel/acpi/boot.c	2003-12-18
08:29:29.000000000 +0530
+++ linux_pciexpress/arch/i386/kernel/acpi/boot.c	2004-01-07
18:20:23.000000000 +0530
@@ -93,6 +93,28 @@
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+extern u64 mmcfg_base_address;
+static int __init acpi_parse_mcfg
+			 (unsigned long phys_addr, unsigned long size)
+{
+	struct acpi_table_mcfg	*mcfg = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr,
size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+	if (mcfg->base_address)
+		mmcfg_base_address =mcfg->base_address;
+	printk(KERN_INFO PREFIX "Local  mcfg address %p\n",
+			mcfg->base_address);
+	return 0;
+}
+#endif /* CONFIG_PCI_EXP_ENHANCED*/
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
@@ -508,6 +530,21 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MCFG not present\n");
+		return 0;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
+		return result;
+	}
+	else if (result > 1) {
+		printk(KERN_WARNING PREFIX "Multiple MCFG tables
exist\n");
+	}
+#endif /*CONFIG_PCI_EXP_ENHANCED*/
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
diff -Naur linux-2.6.0/arch/i386/pci/direct.c
linux_pciexpress/arch/i386/pci/direct.c
--- linux-2.6.0/arch/i386/pci/direct.c	2003-12-18 08:28:28.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/direct.c	2004-01-07
18:16:57.000000000 +0530
@@ -168,6 +168,124 @@
 
 
 /*
+ *We map full Page size on each request. Incidently that's the size we
+ *have for config space too.
+ */
+#ifdef CONFIG_PCI_EXP_ENHANCED
+/* 
+ *On PCI Express capable platform, at the time of kernel initialization
+ *the os would have scanned for mcfg table and set this variable to 
+ *appropriate value.
+ *If PCI Express not supported the variable will have 0 value
+ */
+u64 mmcfg_base_address;
+
+/*
+ *Variable used to store the base address of the last pciexpress device

+ *accessed.
+ */
+u32 pcie_last_accessed_device;
+
+unsigned long pci_exp_set_dev_base (int bus, int dev, int fn)
+{
+	u32 dev_base = 
+		mmcfg_base_address | (bus << 20) | ((PCI_DEVFN (dev,fn))
<<12);
+	if (dev_base != pcie_last_accessed_device){
+		pcie_last_accessed_device = dev_base;
+		set_fixmap (FIX_PCIE_MCFG, dev_base);
+	}
+	return 0;
+}
+
+static int pci_express_conf_read(int seg, int bus, 
+		int devfn, int reg, int len, u32 *value)
+{
+	unsigned long flags;
+	char * virt_addr;
+	int dev = PCI_SLOT (devfn);
+	int fn  = PCI_FUNC (devfn);
+ 
+	if (!value || ((u32)bus > 255) || ((u32)dev > 31) 
+			|| ((u32)fn > 7) || ((u32)reg > 4095)){
+		printk(KERN_ERR "pci_express_conf_read: Invalid
Parameter\n");
+  		return -EINVAL;
+	}
+
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1)){
+		printk(KERN_ERR "pci_express_conf_read: \
+					misalligned transaction\n");
+  		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, dev, fn);
+	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
+ 	switch (len) {
+        case 1:
+		*value = (u8)readb((unsigned long) virt_addr+reg);
+		break;
+        case 2:
+		*value = (u16)readw((unsigned long) virt_addr+reg);
+		break;
+        case 4:
+		*value = (u32)readl((unsigned long) virt_addr+reg);
+		break;
+	}
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+	return 0;
+}
+ 
+static int pci_express_conf_write(int seg, int bus, 
+			int devfn, int reg, int len, u32 value)
+{
+	unsigned long flags;
+	unsigned char * virt_addr;
+	int dev = PCI_SLOT (devfn);
+	int fn  = PCI_FUNC (devfn);
+	
+	if (!value || ((u32)bus > 255) || ((u32)dev > 31) || 
+		((u32)fn > 7) || ((u32)reg > 4095)){
+		printk(KERN_ERR "pci_express_conf_write: \
+					Invalid Parameter\n");
+		return -EINVAL;
+	}
+	
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1)){
+		printk(KERN_ERR "pci_express_conf_write: \
+					misalligned transaction\n");
+  		return -EINVAL;
+	}
+  
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, dev, fn);
+	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
+	
+	switch (len) {
+		case 1:
+			writeb(value,(unsigned long)virt_addr+reg);
+			break;
+		case 2:
+			writew(value,(unsigned long)virt_addr+reg);
+			break;
+	        case 4:
+			writel(value,(unsigned long)virt_addr+reg);
+	                break;
+     	}
+	/* Dummy read to flush PCI write */
+	readl (virt_addr);
+	spin_unlock_irqrestore(&pci_config_lock, flags);	 
+	return 0;
+}
+
+static struct pci_raw_ops pci_express_conf = {
+	.read   =	pci_express_conf_read,
+	.write  =	pci_express_conf_write,
+};
+#endif /* CONFIG_PCI_EXP_ENHANCED */
+
+/*
  * Before we decide to use direct hardware access mechanisms, we try to
do some
  * trivial checks to ensure it at least _seems_ to be working -- we
just test
  * whether bus 00 contains a host bridge (this is similar to checking
@@ -244,6 +362,28 @@
 static int __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
+	unsigned long flags;
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	/*
+ 	 *Check if platform we are running is pci express capable
+  	 */
+	if (mmcfg_base_address == 0){
+		printk(KERN_INFO 
+			"MCFG table entry is not found in ACPI
tables....\n \
+			PCI Express not supported in this platform....\n
\
+			Not enabling Enhanced Configuration....\n");
+	}
+	else {
+		local_irq_save(flags);
+		if (pci_sanity_check(&pci_express_conf)) {
+			local_irq_restore(flags);
+			printk(KERN_INFO "PCI:Using config type
PCIExp\n");
+			raw_pci_ops = &pci_express_conf;
+			return 0;
+		} 
+		local_irq_restore(flags);
+	}
+#endif /* CONFIG_PCI_EXP_ENHANCED */
 
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
diff -Naur linux-2.6.0/arch/i386/pci/Makefile
linux_pciexpress/arch/i386/pci/Makefile
--- linux-2.6.0/arch/i386/pci/Makefile	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/arch/i386/pci/Makefile	2004-01-07
10:59:23.000000000 +0530
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_PCI_EXP_ENHANCED)	+= direct.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI_PCI)		+= acpi.o
diff -Naur linux-2.6.0/drivers/acpi/tables.c
linux_pciexpress/drivers/acpi/tables.c
--- linux-2.6.0/drivers/acpi/tables.c	2003-12-18 08:28:46.000000000
+0530
+++ linux_pciexpress/drivers/acpi/tables.c	2004-01-07
11:03:43.000000000 +0530
@@ -58,6 +58,7 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+	[ACPI_MCFG]		= "MCFG",
 };
 
 /* System Description Table (RSDT/XSDT) */
diff -Naur linux-2.6.0/drivers/pci/pci.c
linux_pciexpress/drivers/pci/pci.c
--- linux-2.6.0/drivers/pci/pci.c	2003-12-18 08:28:38.000000000
+0530
+++ linux_pciexpress/drivers/pci/pci.c	2004-01-07 10:59:23.000000000
+0530
@@ -90,6 +90,8 @@
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
  *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI-EXP
+
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
diff -Naur linux-2.6.0/drivers/pci/proc.c
linux_pciexpress/drivers/pci/proc.c
--- linux-2.6.0/drivers/pci/proc.c	2003-12-18 08:28:57.000000000
+0530
+++ linux_pciexpress/drivers/pci/proc.c	2004-01-07 17:37:04.000000000
+0530
@@ -17,13 +17,29 @@
 #include <asm/byteorder.h>
 
 #define PCI_CFG_SPACE_SIZE 256
+#define PCI_CFG_SPACE_EXP_SIZE 4096
 
 static int proc_initialized;	/* = 0 */
 
+static int pci_cfg_space_size (struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	/* Find whether the device is PCI Express device */
+	int is_pci_express_dev =  pci_find_capability(dev,
PCI_CAP_ID_EXP);
+	if (is_pci_express_dev)
+		return PCI_CFG_SPACE_EXP_SIZE;
+	else
+#endif
+	return PCI_CFG_SPACE_SIZE; 
+}
+
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
 	loff_t new = -1;
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
 
 	lock_kernel();
 	switch (whence) {
@@ -34,11 +50,11 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
-		new = PCI_CFG_SPACE_SIZE + off;
+		new = pci_cfg_space_size(dev) + off;
 		break;
 	}
 	unlock_kernel();
-	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
+	if (new < 0 || new > pci_cfg_space_size(dev))
 		return -EINVAL;
 	return (file->f_pos = new);
 }
@@ -59,7 +75,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+ 		size = pci_cfg_space_size (dev);
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -134,12 +150,14 @@
 	int pos = *ppos;
 	int cnt;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	int size;
+	size = pci_cfg_space_size(dev);
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -384,6 +402,7 @@
 	struct pci_bus *bus = dev->bus;
 	struct proc_dir_entry *de, *e;
 	char name[16];
+	int size;
 
 	if (!proc_initialized)
 		return -EACCES;
@@ -401,7 +420,9 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+
+	size = pci_cfg_space_size(dev);
+	e->size = size;
 
 	return 0;
 }
diff -Naur linux-2.6.0/include/asm-i386/fixmap.h
linux_pciexpress/include/asm-i386/fixmap.h
--- linux-2.6.0/include/asm-i386/fixmap.h	2003-12-18
08:28:06.000000000 +0530
+++ linux_pciexpress/include/asm-i386/fixmap.h	2004-01-07
10:59:23.000000000 +0530
@@ -67,6 +67,9 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings
*/
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	FIX_PCIE_MCFG,
+#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
diff -Naur linux-2.6.0/include/linux/acpi.h
linux_pciexpress/include/linux/acpi.h
--- linux-2.6.0/include/linux/acpi.h	2003-12-18 08:27:58.000000000
+0530
+++ linux_pciexpress/include/linux/acpi.h	2004-01-07
12:02:35.000000000 +0530
@@ -317,6 +317,13 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+struct acpi_table_mcfg {
+	struct acpi_table_header 	header;
+	u8	reserved[8];
+	u64	base_address;
+} __attribute__ ((packed));
+
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +345,7 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+	ACPI_MCFG,
 	ACPI_TABLE_COUNT
 };
 
diff -Naur linux-2.6.0/include/linux/pci.h
linux_pciexpress/include/linux/pci.h
--- linux-2.6.0/include/linux/pci.h	2003-12-18 08:28:49.000000000
+0530
+++ linux_pciexpress/include/linux/pci.h	2004-01-07
10:59:23.000000000 +0530
@@ -198,6 +198,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled
Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI-Express*/
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list
*/
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16
bits) */
 #define PCI_CAP_SIZEOF		4

^ permalink raw reply	[flat|nested] 43+ messages in thread
[parent not found: <183UK-2Re-11@gated-at.bofh.it>]
* [patch] PCI Express Enhanced Config Patch - 2.6.0-test11
@ 2003-12-29 11:32 Durairaj, Sundarapandian
  2003-12-29 11:53 ` Arjan van de Ven
  2003-12-29 11:55 ` Christoph Hellwig
  0 siblings, 2 replies; 43+ messages in thread
From: Durairaj, Sundarapandian @ 2003-12-29 11:32 UTC (permalink / raw)
  To: linux-kernel; +Cc: Seshadri, Harinarayanan, Kondratiev, Vladimir

Hi All,

This is the patch on PCI Express Enhanced configuration for 2.6.0 test11
kernel following up to the Vladamir (Vladimir.Kondratiev@intel.com) and
HariNarayanan (Harinarayanan.Seshadri@intel.com) patches . I tested it
on our i386 platform. 

This patch also implements a mechanism for the kernel to find the
chipset specific mmcfg base address. The kernel will detect the base
address of the chipset through the ACPI table entry and based on that
the PCI subsystem will be initialized.  

Please review this and send in your comments.

Thanks,
Sundar


diff -Naur linux-2.6_src/arch/i386/Kconfig
linux-2.6_pciexpress/arch/i386/Kconfig
--- linux-2.6_src/arch/i386/Kconfig	2003-12-24 14:41:04.000000000
+0530
+++ linux-2.6_pciexpress/arch/i386/Kconfig	2003-12-24
18:34:29.740617408 +0530
@@ -959,7 +959,7 @@
 endmenu
 
 
-menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA, PCI_EXPRESS)"
 
 config X86_VISWS_APIC
 	bool
@@ -976,6 +976,18 @@
 	depends on SMP && !(X86_VISWS || X86_VOYAGER)
 	default y
 
+config PCI_EXP_ENHANCED
+	bool "PCI_EXPRESS (EXPERIMENTAL)" 
+	depends on EXPERIMENTAL 
+	help
+	   PCI Express extends the configuration space from 256 bytes to
4k
+	   bytes. It also defines an enhanced configuration mechanism to
acces
+	   the extended configuration space.
+	   With this option, you can specify that Linux will first
attempt to
+	   access the pci configuration space through enhanced config
access
+	   mechanism (Will work only on PCI Express based system)
otherwise the
+	   pci direct mechanism will be used.
+
 config PCI
 	bool "PCI support" if !X86_VISWS
 	depends on !X86_VOYAGER
diff -Naur linux-2.6_src/arch/i386/kernel/acpi/boot.c
linux-2.6_pciexpress/arch/i386/kernel/acpi/boot.c
--- linux-2.6_src/arch/i386/kernel/acpi/boot.c	2003-11-27
17:47:49.000000000 +0530
+++ linux-2.6_pciexpress/arch/i386/kernel/acpi/boot.c	2003-12-24
18:34:26.844057752 +0530
@@ -93,12 +93,33 @@
 	return ((unsigned char *) base + offset);
 }
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+extern u64 mmcfg_base_address;
+static int __init
+acpi_parse_mcfg (
+	unsigned long		phys_addr,
+	unsigned long		size)
+{
+	struct acpi_table_mcfg	*mcfg = NULL;
 
-#ifdef CONFIG_X86_LOCAL_APIC
-
-static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+	if (!phys_addr || !size)
+		return -EINVAL;
 
+	mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr,
size);
+	if (!mcfg) {
+		printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
+		return -ENODEV;
+	}
+	if (mcfg->base_address)
+		mmcfg_base_address =mcfg->base_address;
+	printk(KERN_INFO PREFIX "Local  mcfg address 0x%x\n",
+			mcfg->base_address);
+	return 0;
+}
+#endif /* CONFIG_PCI_EXP_ENHANCED*/
 
+#ifdef CONFIG_X86_LOCAL_APIC
+static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 static int __init
 acpi_parse_madt (
 	unsigned long		phys_addr,
@@ -508,6 +529,21 @@
 
 #endif /* CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER */
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MCFG not present\n");
+		return 0;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MCFG\n");
+		return result;
+	}
+	else if (result > 1) 
+		printk(KERN_WARNING PREFIX "Multiple MCFG tables
exist\n");
+#endif /*CONFIG_PCI_EXP_ENHANCED*/
+
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	if (acpi_lapic && acpi_ioapic) {
 		smp_found_config = 1;
diff -Naur linux-2.6_src/arch/i386/pci/direct.c
linux-2.6_pciexpress/arch/i386/pci/direct.c
--- linux-2.6_src/arch/i386/pci/direct.c	2003-11-27
17:47:49.000000000 +0530
+++ linux-2.6_pciexpress/arch/i386/pci/direct.c	2003-12-24
18:34:29.432664224 +0530
@@ -168,6 +168,123 @@
 
 
 /*
+	We map full Page size on each request. Incidently that's the
size we
+	have for config space too.
+*/
+#ifdef CONFIG_PCI_EXP_ENHANCED
+u64 mmcfg_base_address;
+
+/* mmcfg base address will be initalised by the os initalisation 
+ * code on PCI Express capable platform 
+ */
+static int is_pci_exp_platform(void )
+{
+/* 
+	At the time of initialisation of  the os would have 
+	scanned for mcfg table and set this variable to appropriate 
+	value If PCI Express not supported the variable 
+	will have 0 value
+*/
+	if (mmcfg_base_address == 0){
+		printk(KERN_INFO "MCFG table entry is not found in ACPI
tables....\n");
+		printk(KERN_INFO " PCI Express not supported in this
platform....\n");
+		printk(KERN_INFO " Not enabling Enhanced
Configuration....\n");
+		return 0;
+	}
+	return 1;
+}
+/*
+ Variable used to store the base address of the last pciexpress device 
+  accessed.
+ */
+u32 pcie_last_accessed_device;
+
+unsigned long pci_exp_set_dev_base (int bus, int dev, int fn)
+{
+	u32 dev_base = 
+		mmcfg_base_address | (bus << 20) | ((PCI_DEVFN (dev,fn))
<<12);
+	if (dev_base != pcie_last_accessed_device){
+		pcie_last_accessed_device = dev_base;
+		set_fixmap (FIX_PCIE_MCFG, dev_base);
+	}
+}
+
+static int pci_express_conf_read(int seg, int bus, int devfn, int reg,
int len, u32 *value)
+{
+	 unsigned long flags;
+	 unsigned long base_address;
+	 char * virt_addr;
+	 int dev = PCI_SLOT (devfn);
+	 int fn  = PCI_FUNC (devfn);
+ 
+  if (!value || ((u32)bus > 255) || ((u32)dev > 31) || ((u32)fn > 7) ||
((u32)reg > 4095))
+  	return -EINVAL;
+
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1))
+  	return -EINVAL;
+
+  spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, dev, fn);
+	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
+  switch (len) {
+        case 1:
+       		*value = (u8)readb((unsigned long)
virt_addr+reg);
+                break;
+        case 2:
+       		*value = (u16)readw((unsigned long)
virt_addr+reg);
+                break;
+        case 4:
+       		*value = (u32)readl((unsigned long)
virt_addr+reg);
+                break;
+	}
+  spin_unlock_irqrestore(&pci_config_lock, flags);
+  return 0;
+}
+ 
+static int pci_express_conf_write(int seg, int bus, int devfn, int reg,
int len, u32 value)
+{
+	unsigned long flags;
+	unsigned long base_address;
+	unsigned char * virt_addr;
+	int dev = PCI_SLOT (devfn);
+	int fn  = PCI_FUNC (devfn);
+	
+	if (!value || ((u32)bus > 255) || ((u32)dev > 31) || ((u32)fn >
7) || ((u32)reg > 4095))
+		return -EINVAL;
+	
+	/* Shoot misalligned transaction now */
+	if (reg & (len-1))
+  	return -EINVAL;
+  
+	spin_lock_irqsave(&pci_config_lock, flags);
+	pci_exp_set_dev_base(bus, dev, fn);
+	virt_addr = (char *) (fix_to_virt(FIX_PCIE_MCFG));
+	
+	switch (len) {
+		case 1:
+			writeb(value,(unsigned long)virt_addr+reg);
+			break;
+		case 2:
+			writew(value,(unsigned long)virt_addr+reg);
+       		        break;
+	        case 4:
+			writel(value,(unsigned long)virt_addr+reg);
+	                break;
+     	}
+ 	/* Dummy read to flush PCI write */
+	readl (virt_addr);
+	spin_unlock_irqrestore(&pci_config_lock, flags);	 
+	return 0;
+}
+
+static struct pci_raw_ops pci_express_conf = {
+				.read   =        pci_express_conf_read,
+        .write  =        pci_express_conf_write,
+};
+#endif /* CONFIG_PCI_EXP_ENHANCED */
+
+/*
  * Before we decide to use direct hardware access mechanisms, we try to
do some
  * trivial checks to ensure it at least _seems_ to be working -- we
just test
  * whether bus 00 contains a host bridge (this is similar to checking
@@ -244,6 +361,22 @@
 static int __init pci_direct_init(void)
 {
 	struct resource *region, *region2;
+	unsigned long flags;
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	local_irq_save(flags);
+	/*
+	 *	Check if platform we are running is pci express capable
+	 */
+	 if( is_pci_exp_platform() != 0){
+		if (pci_sanity_check(&pci_express_conf)) {
+			local_irq_restore(flags);
+			printk(KERN_INFO "PCI:Using config type
PCIExp\n");
+			raw_pci_ops = &pci_express_conf;
+			return 0;
+		} 
+	}
+	local_irq_restore(flags);
+#endif /* CONFIG_PCI_EXP_ENHANCED */
 
 	if ((pci_probe & PCI_PROBE_CONF1) == 0)
 		goto type2;
diff -Naur linux-2.6_src/arch/i386/pci/Makefile
linux-2.6_pciexpress/arch/i386/pci/Makefile
--- linux-2.6_src/arch/i386/pci/Makefile	2003-11-27
17:47:49.000000000 +0530
+++ linux-2.6_pciexpress/arch/i386/pci/Makefile	2003-12-24
18:34:29.438663312 +0530
@@ -2,6 +2,7 @@
 
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
+obj-$(CONFIG_PCI_EXP_ENHANCED)	+= direct.o
 
 pci-y				:= fixup.o
 pci-$(CONFIG_ACPI_PCI)		+= acpi.o
diff -Naur linux-2.6_src/drivers/acpi/tables.c
linux-2.6_pciexpress/drivers/acpi/tables.c
--- linux-2.6_src/drivers/acpi/tables.c	2003-11-27 17:48:39.000000000
+0530
+++ linux-2.6_pciexpress/drivers/acpi/tables.c	2003-12-24
18:34:38.048354440 +0530
@@ -58,6 +58,9 @@
 	[ACPI_SSDT]		= "SSDT",
 	[ACPI_SPMI]		= "SPMI",
 	[ACPI_HPET]		= "HPET",
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	[ACPI_MCFG]		= "MCFG",
+#endif
 };
 
 /* System Description Table (RSDT/XSDT) */
diff -Naur linux-2.6_src/drivers/pci/pci.c
linux-2.6_pciexpress/drivers/pci/pci.c
--- linux-2.6_src/drivers/pci/pci.c	2003-11-27 17:48:59.000000000
+0530
+++ linux-2.6_pciexpress/drivers/pci/pci.c	2003-12-24
18:34:41.216872752 +0530
@@ -90,6 +90,8 @@
  *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
  *
  *  %PCI_CAP_ID_PCIX         PCI-X
+ *  %PCI_CAP_ID_EXP          PCI-EXP
+
  */
 int
 pci_find_capability(struct pci_dev *dev, int cap)
diff -Naur linux-2.6_src/drivers/pci/proc.c
linux-2.6_pciexpress/drivers/pci/proc.c
--- linux-2.6_src/drivers/pci/proc.c	2003-11-27 17:48:59.000000000
+0530
+++ linux-2.6_pciexpress/drivers/pci/proc.c	2003-12-24
18:34:41.249867736 +0530
@@ -18,11 +18,23 @@
 
 #define PCI_CFG_SPACE_SIZE 256
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+#define PCI_CFG_SPACE_EXP_SIZE 4096
+#endif
+ 
+
 static int proc_initialized;	/* = 0 */
 
 static loff_t
 proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
 {
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	const struct inode *ino = file->f_dentry->d_inode;
+	const struct proc_dir_entry *dp = PDE(ino);
+	struct pci_dev *dev = dp->data;
+	/* Find whether the device is PCI Express device */
+	int is_pci_express_dev =  pci_find_capability(dev,
PCI_CAP_ID_EXP);
+#endif /*CONFIG_PCI_EXP_ENHANCED*/
 	loff_t new = -1;
 
 	lock_kernel();
@@ -34,12 +46,22 @@
 		new = file->f_pos + off;
 		break;
 	case 2:
+#ifdef CONFIG_PCI_EXP_ENHANCED
+		if (is_pci_express_dev)
+			new = PCI_CFG_SPACE_EXP_SIZE + off;
+		else
+#endif /*CONFIG_PCI_EXP_ENHANCED*/
 		new = PCI_CFG_SPACE_SIZE + off;
 		break;
 	}
 	unlock_kernel();
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	if (is_pci_express_dev && (new < 0 || new >
PCI_CFG_SPACE_EXP_SIZE))
+		return -EINVAL;
+#else
 	if (new < 0 || new > PCI_CFG_SPACE_SIZE)
 		return -EINVAL;
+#endif /*CONFIG_PCI_EXP_ENHANCED */
 	return (file->f_pos = new);
 }
 
@@ -59,7 +81,12 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = PCI_CFG_SPACE_SIZE;
+#ifdef CONFIG_PCI_EXP_ENHANCED
+		if (pci_find_capability(dev,PCI_CAP_ID_EXP))
+			size = PCI_CFG_SPACE_EXP_SIZE;
+		else
+#endif /*CONFIG_PCI_EXP_ENHANCED */
+ 		size = PCI_CFG_SPACE_SIZE;
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -134,12 +161,21 @@
 	int pos = *ppos;
 	int cnt;
 
-	if (pos >= PCI_CFG_SPACE_SIZE)
+	int size;
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	if (pci_find_capability(dev,PCI_CAP_ID_EXP))
+		size = PCI_CFG_SPACE_EXP_SIZE;
+	else
+#endif /* CONFIG_PCI_EXP_ENHANCED */
+	size = PCI_CFG_SPACE_SIZE;
+
+
+	if (pos >= size)
 		return 0;
-	if (nbytes >= PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE;
-	if (pos + nbytes > PCI_CFG_SPACE_SIZE)
-		nbytes = PCI_CFG_SPACE_SIZE - pos;
+	if (nbytes >= size)
+		nbytes = size;
+	if (pos + nbytes > size)
+		nbytes = size - pos;
 	cnt = nbytes;
 
 	if (!access_ok(VERIFY_READ, buf, cnt))
@@ -384,6 +420,7 @@
 	struct pci_bus *bus = dev->bus;
 	struct proc_dir_entry *de, *e;
 	char name[16];
+	int size;
 
 	if (!proc_initialized)
 		return -EACCES;
@@ -401,7 +438,14 @@
 		return -ENOMEM;
 	e->proc_fops = &proc_bus_pci_operations;
 	e->data = dev;
-	e->size = PCI_CFG_SPACE_SIZE;
+
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	if (pci_find_capability(dev,PCI_CAP_ID_EXP))
+		size = PCI_CFG_SPACE_EXP_SIZE;
+	else
+#endif /*CONFIG_PCI_EXP_ENHANCED */
+	size = PCI_CFG_SPACE_SIZE;
+	e->size = size;
 
 	return 0;
 }
diff -Naur linux-2.6_src/include/asm-i386/fixmap.h
linux-2.6_pciexpress/include/asm-i386/fixmap.h
--- linux-2.6_src/include/asm-i386/fixmap.h	2003-11-27
17:47:00.000000000 +0530
+++ linux-2.6_pciexpress/include/asm-i386/fixmap.h	2003-12-24
18:34:19.213217816 +0530
@@ -67,6 +67,9 @@
 	FIX_KMAP_BEGIN,	/* reserved pte's for temporary kernel mappings
*/
 	FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
 #endif
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	FIX_PCIE_MCFG,
+#endif
 #ifdef CONFIG_ACPI_BOOT
 	FIX_ACPI_BEGIN,
 	FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
diff -Naur linux-2.6_src/include/linux/acpi.h
linux-2.6_pciexpress/include/linux/acpi.h
--- linux-2.6_src/include/linux/acpi.h	2003-11-27 17:47:18.000000000
+0530
+++ linux-2.6_pciexpress/include/linux/acpi.h	2003-12-24
18:34:21.000000000 +0530
@@ -317,6 +317,15 @@
 	char				ec_id[0];
 } __attribute__ ((packed));
 
+#ifdef CONFIG_PCI_EXP_ENHANCED
+struct acpi_table_mcfg {
+	struct acpi_table_header 	header;
+	u8	reserved[8];
+	u64	base_address;
+} __attribute__ ((packed));
+#endif
+
+
 /* Table Handlers */
 
 enum acpi_table_id {
@@ -338,6 +347,9 @@
 	ACPI_SSDT,
 	ACPI_SPMI,
 	ACPI_HPET,
+#ifdef CONFIG_PCI_EXP_ENHANCED
+	ACPI_MCFG,
+#endif
 	ACPI_TABLE_COUNT
 };
 
diff -Naur linux-2.6_src/include/linux/pci.h
linux-2.6_pciexpress/include/linux/pci.h
--- linux-2.6_src/include/linux/pci.h	2003-11-27 17:47:11.000000000
+0530
+++ linux-2.6_pciexpress/include/linux/pci.h	2003-12-24
18:34:20.000000000 +0530
@@ -198,6 +198,7 @@
 #define  PCI_CAP_ID_MSI		0x05	/* Message Signalled
Interrupts */
 #define  PCI_CAP_ID_CHSWP	0x06	/* CompactPCI HotSwap */
 #define  PCI_CAP_ID_PCIX	0x07	/* PCI-X */
+#define  PCI_CAP_ID_EXP 	0x10	/* PCI-Express*/
 #define PCI_CAP_LIST_NEXT	1	/* Next capability in the list
*/
 #define PCI_CAP_FLAGS		2	/* Capability defined flags (16
bits) */
 #define PCI_CAP_SIZEOF		4

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

end of thread, other threads:[~2004-02-01 21:42 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-01-28  9:38 [patch] PCI Express Enhanced Config Patch - 2.6.0-test11 Durairaj, Sundarapandian
2004-01-28 14:42 ` Vladimir Kondratiev
2004-01-28 14:54   ` Christoph Hellwig
2004-01-28 15:00   ` Martin Mares
2004-01-28 15:18 ` Matthew Wilcox
  -- strict thread matches above, loose matches on Subject: below --
2004-01-30 16:58 Nakajima, Jun
2004-01-29 11:32 Durairaj, Sundarapandian
2004-01-29 15:09 ` Matthew Wilcox
2004-01-29 15:59   ` Matthew Wilcox
2004-01-29 16:05     ` Linus Torvalds
2004-01-29 16:42       ` Matthew Wilcox
2004-01-29 16:52         ` Linus Torvalds
2004-01-31 21:57         ` Eric W. Biederman
2004-02-01  4:41           ` Grant Grundler
2004-02-01  5:10           ` Matthew Wilcox
2004-02-01 11:00             ` Eric W. Biederman
2004-02-01 15:18               ` Matthew Wilcox
2004-02-01 18:28                 ` Eric W. Biederman
2004-02-01 20:11                   ` Matthew Wilcox
2004-02-01 21:35                     ` Eric W. Biederman
2004-02-01 11:10             ` Eric W. Biederman
2004-01-29 18:09       ` Greg KH
2004-01-30 16:33         ` Greg KH
2004-01-22 10:21 Durairaj, Sundarapandian
2004-01-22 10:44 ` Andrew Morton
2004-01-22 11:09 ` Martin Mares
2004-01-22 13:12 ` Andi Kleen
2004-01-22 18:21   ` Alan Cox
2004-01-22 19:40     ` Randy.Dunlap
2004-01-23 19:19       ` Pavel Machek
2004-01-23 19:31         ` Martin Mares
2004-01-23 20:08           ` Stefan Smietanowski
2004-01-22 16:40 ` Grant Grundler
2004-01-22 17:00 ` Greg KH
2004-01-07 16:44 Nakajima, Jun
2004-01-07 12:59 Durairaj, Sundarapandian
2004-01-07 14:08 ` Meelis Roos
2004-01-07 17:34 ` Vladimir Kondratiev
     [not found] <183UK-2Re-11@gated-at.bofh.it>
2003-12-29 19:12 ` Andi Kleen
2003-12-29 11:32 Durairaj, Sundarapandian
2003-12-29 11:53 ` Arjan van de Ven
2003-12-29 11:55 ` Christoph Hellwig
2003-12-29 12:51   ` Johan Sjoholm

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).