patch-2.2.18 linux/arch/ppc/kernel/pci.c

Next file: linux/arch/ppc/kernel/pmac_pci.c
Previous file: linux/arch/ppc/kernel/openpic.c
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
@@ -10,15 +10,20 @@
 #include <linux/init.h>
 #include <linux/config.h>
 #include <linux/openpic.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
 
 #include <asm/processor.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#include <asm/pci.h>
 #include <asm/residual.h>
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/gg2.h>
+#include <asm/uaccess.h>
 
 #include "pci.h"
 
@@ -105,3 +110,156 @@
 	}
 }
 #endif
+
+
+void *
+pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical)
+{
+	if (!ppc_md.pci_dev_io_base) {
+		/* Please, someone fix this for non-pmac machines, we
+		 * need either the virtual or physical PCI IO base
+		 */
+		return 0;
+	}
+	return ppc_md.pci_dev_io_base(bus, devfn, physical);
+}
+
+void *
+pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+	/* Default memory base is 0 (1:1 mapping) */
+	if (!ppc_md.pci_dev_mem_base) {
+		/* Please, someone fix this for non-pmac machines.*/
+		return 0;
+	}
+	return ppc_md.pci_dev_mem_base(bus, devfn);
+}
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int
+pci_dev_root_bridge(unsigned char bus, unsigned char devfn)
+{
+	/* Defaults to 0 */
+	if (!ppc_md.pci_dev_root_bridge)
+		return 0;
+	return ppc_md.pci_dev_root_bridge(bus, devfn);
+}
+
+/*
+ * Those syscalls are derived from the Alpha versions, they
+ * allow userland apps to retreive the per-device iobase and
+ * mem-base. They also provide wrapper for userland to do
+ * config space accesses.
+ * The "host_number" returns the number of the Uni-N sub bridge
+ */
+
+asmlinkage int
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+		   unsigned long off, unsigned long len,
+		   unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	long err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!pcibios_present())
+		return -ENOSYS;
+	
+	switch (len) {
+	case 1:
+		err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
+		put_user(ubyte, buf);
+		break;
+	case 2:
+		err = pcibios_read_config_word(bus, dfn, off, &ushort);
+		put_user(ushort, (unsigned short *)buf);
+		break;
+	case 4:
+		err = pcibios_read_config_dword(bus, dfn, off, &uint);
+		put_user(uint, (unsigned int *)buf);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+asmlinkage int
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+		    unsigned long off, unsigned long len,
+		    unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	long err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!pcibios_present())
+		return -ENOSYS;
+
+	switch (len) {
+	case 1:
+		err = get_user(ubyte, buf);
+		if (err)
+			break;
+		err = pcibios_write_config_byte(bus, dfn, off, ubyte);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	case 2:
+		err = get_user(ushort, (unsigned short *)buf);
+		if (err)
+			break;
+		err = pcibios_write_config_word(bus, dfn, off, ushort);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	case 4:
+		err = get_user(uint, (unsigned int *)buf);
+		if (err)
+			break;
+		err = pcibios_write_config_dword(bus, dfn, off, uint);
+		if (err != PCIBIOS_SUCCESSFUL) {
+			err = -EFAULT;
+		}
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+	return err;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory.  Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+	long result = -EOPNOTSUPP;
+	
+	switch (which) {
+	case IOBASE_BRIDGE_NUMBER:
+		return (long)pci_dev_root_bridge(bus, devfn);
+	case IOBASE_MEMORY:
+		return (long)pci_dev_mem_base(bus, devfn);
+	case IOBASE_IO:
+		result = (long)pci_dev_io_base(bus, devfn, 1);
+		if (result == 0)
+			result = -EOPNOTSUPP;
+		break;
+	}
+
+	return result;
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)