From 7eae642f75e0f7fbce7c37b2dfe0641ff1e9ebfd Mon Sep 17 00:00:00 2001
From: "David S. Miller" <davem@sunset.davemloft.net>
Date: Thu, 9 Feb 2006 22:20:01 -0800
Subject: [SPARC64]: Implement SUN4V PCI config space access.

Signed-off-by: David S. Miller <davem@davemloft.net>
---
 arch/sparc64/kernel/pci_sun4v.c     | 40 +++++++++++++++++++++++++++----
 arch/sparc64/kernel/pci_sun4v.h     |  9 +++++++
 arch/sparc64/kernel/pci_sun4v_asm.S | 48 +++++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+), 4 deletions(-)

(limited to 'arch')

diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 1d61353e26..abd9bfb245 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -74,15 +74,47 @@ struct pci_iommu_ops pci_sun4v_iommu_ops = {
 static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
 				  int where, int size, u32 *value)
 {
-	/* XXX Implement me! XXX */
-	return 0;
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned long devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	ret = pci_sun4v_config_get(devhandle,
+				   HV_PCI_DEVICE_BUILD(bus, device, func),
+				   where, size);
+	switch (size) {
+	case 1:
+		*value = ret & 0xff;
+		break;
+	case 2:
+		*value = ret & 0xffff;
+		break;
+	case 4:
+		*value = ret & 0xffffffff;
+		break;
+	};
+
+
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
 				   int where, int size, u32 value)
 {
-	/* XXX Implement me! XXX */
-	return 0;
+	struct pci_pbm_info *pbm = bus_dev->sysdata;
+	unsigned long devhandle = pbm->devhandle;
+	unsigned int bus = bus_dev->number;
+	unsigned int device = PCI_SLOT(devfn);
+	unsigned int func = PCI_FUNC(devfn);
+	unsigned long ret;
+
+	ret = pci_sun4v_config_put(devhandle,
+				   HV_PCI_DEVICE_BUILD(bus, device, func),
+				   where, size, value);
+
+	return PCIBIOS_SUCCESSFUL;
 }
 
 static struct pci_ops pci_sun4v_ops = {
diff --git a/arch/sparc64/kernel/pci_sun4v.h b/arch/sparc64/kernel/pci_sun4v.h
index d3ac7ece4b..5c7ed2ca15 100644
--- a/arch/sparc64/kernel/pci_sun4v.h
+++ b/arch/sparc64/kernel/pci_sun4v.h
@@ -16,5 +16,14 @@ extern unsigned long pci_sun4v_iommu_map(unsigned long devhandle,
 extern unsigned long pci_sun4v_iommu_demap(unsigned long devhandle,
 					   unsigned long tsbid,
 					   unsigned long num_ttes);
+extern unsigned long pci_sun4v_config_get(unsigned long devhandle,
+					  unsigned long pci_device,
+					  unsigned long config_offset,
+					  unsigned long size);
+extern int pci_sun4v_config_put(unsigned long devhandle,
+				unsigned long pci_device,
+				unsigned long config_offset,
+				unsigned long size,
+				unsigned long data);
 
 #endif /* !(_PCI_SUN4V_H) */
diff --git a/arch/sparc64/kernel/pci_sun4v_asm.S b/arch/sparc64/kernel/pci_sun4v_asm.S
index fd2fe0edf1..2f1147146a 100644
--- a/arch/sparc64/kernel/pci_sun4v_asm.S
+++ b/arch/sparc64/kernel/pci_sun4v_asm.S
@@ -54,3 +54,51 @@ pci_sun4v_iommu_demap:
 	ta	HV_FAST_TRAP
 	retl
 	 mov	%o1, %o0
+
+	/* %o0: devhandle
+	 * %o1:	pci_device
+	 * %o2:	pci_config_offset
+	 * %o3:	size
+	 *
+	 * returns %o0:	data
+	 *
+	 * If there is an error, the data will be returned
+	 * as all 1's.
+	 */
+	.globl	pci_sun4v_config_get
+pci_sun4v_config_get:
+	mov	%o3, %o4
+	mov	%o2, %o3
+	mov	%o1, %o2
+	mov	%o0, %o1
+	mov	HV_FAST_PCI_CONFIG_GET, %o0
+	ta	HV_FAST_TRAP
+	brnz,a,pn %o1, 1f
+	 mov	-1, %o2
+1:	retl
+	 mov	%o2, %o0
+
+	/* %o0: devhandle
+	 * %o1:	pci_device
+	 * %o2:	pci_config_offset
+	 * %o3:	size
+	 * %o4:	data
+	 *
+	 * returns %o0:	status
+	 *
+	 * status will be zero if the operation completed
+	 * successfully, else -1 if not
+	 */
+	.globl	pci_sun4v_config_put
+pci_sun4v_config_put:
+	mov	%o3, %o4
+	mov	%o2, %o3
+	mov	%o1, %o2
+	mov	%o0, %o1
+	mov	HV_FAST_PCI_CONFIG_PUT, %o0
+	ta	HV_FAST_TRAP
+	brnz,a,pn %o1, 1f
+	 mov	-1, %o1
+1:	retl
+	 mov	%o1, %o0
+
-- 
cgit v1.2.2