aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/io/drivers/ioconfig_bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/sn/io/drivers/ioconfig_bus.c')
-rw-r--r--arch/ia64/sn/io/drivers/ioconfig_bus.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/arch/ia64/sn/io/drivers/ioconfig_bus.c b/arch/ia64/sn/io/drivers/ioconfig_bus.c
new file mode 100644
index 00000000000000..0d043d3f25eb68
--- /dev/null
+++ b/arch/ia64/sn/io/drivers/ioconfig_bus.c
@@ -0,0 +1,401 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * ioconfig_bus - SGI's Persistent PCI Bus Numbering.
+ *
+ * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+
+#include <asm/sn/sgi.h>
+#include <linux/devfs_fs.h>
+#include <linux/devfs_fs_kernel.h>
+#include <asm/io.h>
+#include <asm/sn/iograph.h>
+#include <asm/sn/invent.h>
+#include <asm/sn/hcl.h>
+#include <asm/sn/labelcl.h>
+#include <asm//sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/ioconfig_bus.h>
+
+#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING"
+#define SGI_IOCONFIG_BUS_VERSION "1.0"
+
+/*
+ * Some Global definitions.
+ */
+static vertex_hdl_t ioconfig_bus_handle;
+static unsigned long ioconfig_bus_debug;
+
+#ifdef IOCONFIG_BUS_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static u64 ioconfig_file;
+static u64 ioconfig_file_size;
+static u64 ioconfig_activated;
+static char ioconfig_kernopts[128];
+
+/*
+ * For debugging purpose .. hardcode a table ..
+ */
+struct ascii_moduleid *ioconfig_bus_table;
+u64 ioconfig_bus_table_size;
+
+
+static int free_entry;
+static int new_entry;
+
+int next_basebus_number;
+
+void
+ioconfig_get_busnum(char *io_moduleid, int *bus_num)
+{
+ struct ascii_moduleid *temp;
+ int index;
+
+ DBG("ioconfig_get_busnum io_moduleid %s\n", io_moduleid);
+
+ *bus_num = -1;
+ temp = ioconfig_bus_table;
+ for (index = 0; index < free_entry; temp++, index++) {
+ if ( (io_moduleid[0] == temp->io_moduleid[0]) &&
+ (io_moduleid[1] == temp->io_moduleid[1]) &&
+ (io_moduleid[2] == temp->io_moduleid[2]) &&
+ (io_moduleid[4] == temp->io_moduleid[4]) &&
+ (io_moduleid[5] == temp->io_moduleid[5]) ) {
+ *bus_num = index * 0x10;
+ return;
+ }
+ }
+
+ /*
+ * New IO Brick encountered.
+ */
+ if (((int)io_moduleid[0]) == 0) {
+ DBG("ioconfig_get_busnum: Invalid Module Id given %s\n", io_moduleid);
+ return;
+ }
+
+ io_moduleid[3] = '#';
+ strcpy((char *)&(ioconfig_bus_table[free_entry].io_moduleid), io_moduleid);
+ *bus_num = free_entry * 0x10;
+ free_entry++;
+}
+
+static void
+dump_ioconfig_table(void)
+{
+
+ int index = 0;
+ struct ascii_moduleid *temp;
+
+ temp = ioconfig_bus_table;
+ while (index < free_entry) {
+ DBG("ASSCI Module ID %s\n", temp->io_moduleid);
+ temp++;
+ index++;
+ }
+}
+
+/*
+ * nextline
+ * This routine returns the nextline in the buffer.
+ */
+int nextline(char *buffer, char **next, char *line)
+{
+
+ char *temp;
+
+ if (buffer[0] == 0x0) {
+ return(0);
+ }
+
+ temp = buffer;
+ while (*temp != 0) {
+ *line = *temp;
+ if (*temp != '\n'){
+ *line = *temp;
+ temp++; line++;
+ } else
+ break;
+ }
+
+ if (*temp == 0)
+ *next = temp;
+ else
+ *next = ++temp;
+
+ return(1);
+}
+
+/*
+ * build_pcibus_name
+ * This routine parses the ioconfig contents read into
+ * memory by ioconfig command in EFI and builds the
+ * persistent pci bus naming table.
+ */
+void
+build_moduleid_table(char *file_contents, struct ascii_moduleid *table)
+{
+ /*
+ * Read the whole file into memory.
+ */
+ int rc;
+ char *name;
+ char *temp;
+ char *next;
+ char *current;
+ char *line;
+ struct ascii_moduleid *moduleid;
+
+ line = kmalloc(256, GFP_KERNEL);
+ memset(line, 0,256);
+ name = kmalloc(125, GFP_KERNEL);
+ memset(name, 0, 125);
+ moduleid = table;
+ current = file_contents;
+ while (nextline(current, &next, line)){
+
+ DBG("current 0x%lx next 0x%lx\n", current, next);
+
+ temp = line;
+ /*
+ * Skip all leading Blank lines ..
+ */
+ while (isspace(*temp))
+ if (*temp != '\n')
+ temp++;
+ else
+ break;
+
+ if (*temp == '\n') {
+ current = next;
+ memset(line, 0, 256);
+ continue;
+ }
+
+ /*
+ * Skip comment lines
+ */
+ if (*temp == '#') {
+ current = next;
+ memset(line, 0, 256);
+ continue;
+ }
+
+ /*
+ * Get the next free entry in the table.
+ */
+ rc = sscanf(temp, "%s", name);
+ strcpy(&moduleid->io_moduleid[0], name);
+ DBG("Found %s\n", name);
+ moduleid++;
+ free_entry++;
+ current = next;
+ memset(line, 0, 256);
+ }
+
+ new_entry = free_entry;
+ kfree(line);
+ kfree(name);
+
+ return;
+}
+
+void
+ioconfig_bus_init(void)
+{
+
+ struct ia64_sal_retval ret_stuff;
+ u64 *temp;
+ int cnode;
+
+ DBG("ioconfig_bus_init called.\n");
+
+ for (cnode = 0; cnode < numnodes; cnode++) {
+ nasid_t nasid;
+ /*
+ * Make SAL call to get the address of the bus configuration table.
+ */
+ ret_stuff.status = (uint64_t)0;
+ ret_stuff.v0 = (uint64_t)0;
+ ret_stuff.v1 = (uint64_t)0;
+ ret_stuff.v2 = (uint64_t)0;
+ nasid = COMPACT_TO_NASID_NODEID(cnode);
+ SAL_CALL(ret_stuff, SN_SAL_BUS_CONFIG, 0, nasid, 0, 0, 0, 0, 0);
+ temp = (u64 *)TO_NODE_CAC(nasid, ret_stuff.v0);
+ ioconfig_file = *temp;
+ DBG("ioconfig_bus_init: Nasid %d ret_stuff.v0 0x%lx\n", nasid,
+ ret_stuff.v0);
+ if (ioconfig_file) {
+ ioconfig_file_size = ret_stuff.v1;
+ ioconfig_file = (ioconfig_file | CACHEABLE_MEM_SPACE);
+ ioconfig_activated = 1;
+ break;
+ }
+ }
+
+ DBG("ioconfig_bus_init: ret_stuff.v0 %p ioconfig_file %p %d\n",
+ ret_stuff.v0, (void *)ioconfig_file, (int)ioconfig_file_size);
+
+ ioconfig_bus_table = kmalloc( 512, GFP_KERNEL );
+ memset(ioconfig_bus_table, 0, 512);
+
+ /*
+ * If ioconfig options are given on the bootline .. take it.
+ */
+ if (*ioconfig_kernopts != '\0') {
+ /*
+ * ioconfig="..." kernel options given.
+ */
+ DBG("ioconfig_bus_init: Kernel Options given.\n");
+ (void) build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table);
+ (void) dump_ioconfig_table();
+ return;
+ }
+
+ if (ioconfig_activated) {
+ DBG("ioconfig_bus_init: ioconfig file given.\n");
+ (void) build_moduleid_table((char *)ioconfig_file, ioconfig_bus_table);
+ (void) dump_ioconfig_table();
+ } else {
+ DBG("ioconfig_bus_init: ioconfig command not executed in prom\n");
+ }
+
+}
+
+void
+ioconfig_bus_new_entries(void)
+{
+
+
+ int index = 0;
+ struct ascii_moduleid *temp;
+
+ if ((ioconfig_activated) && (free_entry > new_entry)) {
+ printk("### Please add the following new IO Bricks Module ID \n");
+ printk("### to your Persistent Bus Numbering Config File\n");
+ } else
+ return;
+
+ index = new_entry;
+ temp = &ioconfig_bus_table[index];
+ while (index < free_entry) {
+ printk("%s\n", (char *)temp);
+ temp++;
+ index++;
+ }
+ printk("### End\n");
+
+}
+static int ioconfig_bus_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+
+ struct ioconfig_parm parm;
+
+ /*
+ * Copy in the parameters.
+ */
+ copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm));
+ parm.number = free_entry - new_entry;
+ parm.ioconfig_activated = ioconfig_activated;
+ copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm));
+ copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry));
+
+ return 0;
+}
+
+/*
+ * ioconfig_bus_open - Opens the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_open(struct inode * inode, struct file * filp)
+{
+ if (ioconfig_bus_debug) {
+ DBG("ioconfig_bus_open called.\n");
+ }
+
+ return(0);
+
+}
+
+/*
+ * ioconfig_bus_close - Closes the special device node "/dev/hw/.ioconfig_bus".
+ */
+static int ioconfig_bus_close(struct inode * inode, struct file * filp)
+{
+
+ if (ioconfig_bus_debug) {
+ DBG("ioconfig_bus_close called.\n");
+ }
+
+ return(0);
+}
+
+struct file_operations ioconfig_bus_fops = {
+ ioctl:ioconfig_bus_ioctl,
+ open:ioconfig_bus_open, /* open */
+ release:ioconfig_bus_close /* release */
+};
+
+
+/*
+ * init_ifconfig_bus() - Boot time initialization. Ensure that it is called
+ * after devfs has been initialized.
+ *
+ */
+int init_ioconfig_bus(void)
+{
+ ioconfig_bus_handle = NULL;
+ ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus",
+ 0, DEVFS_FL_AUTO_DEVNUM,
+ 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ &ioconfig_bus_fops, NULL);
+
+ if (ioconfig_bus_handle == NULL) {
+ panic("Unable to create SGI PERSISTENT BUS NUMBERING Driver.\n");
+ }
+
+ return(0);
+
+}
+
+static int __init ioconfig_bus_setup (char *str)
+{
+
+ char *temp;
+
+ DBG("ioconfig_bus_setup: Kernel Options %s\n", str);
+
+ temp = (char *)ioconfig_kernopts;
+ memset(temp, 0, 128);
+ while ( (*str != '\0') && !isspace (*str) ) {
+ if (*str == ',') {
+ *temp = '\n';
+ temp++;
+ str++;
+ continue;
+ }
+ *temp = *str;
+ temp++;
+ str++;
+ }
+
+ return(0);
+
+}
+__setup("ioconfig=", ioconfig_bus_setup);