From: Mark Huang Date: Sat, 20 Aug 2005 21:44:06 +0000 (+0000) Subject: - sync fedora branch X-Git-Tag: before-fedora-2_6_18-1_2239_FC5-vs2_0_2_2-rc6-merge~128 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=863ea6b36229d27fae396076b3158738057765f1;p=linux-2.6.git - sync fedora branch --- diff --git a/arch/ia64/sn/io/Makefile b/arch/ia64/sn/io/Makefile deleted file mode 100644 index 868f2b1a1..000000000 --- a/arch/ia64/sn/io/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# arch/ia64/sn/io/Makefile -# -# 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. -# -# Copyright (C) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn io routines. -# - -obj-y += xswitch.o cdl.o snia_if.o \ - io.o machvec/ drivers/ platform_init/ sn2/ hwgfs/ diff --git a/arch/ia64/sn/io/cdl.c b/arch/ia64/sn/io/cdl.c deleted file mode 100644 index eff8d9ce8..000000000 --- a/arch/ia64/sn/io/cdl.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include "asm/sn/ioerror_handling.h" -#include - -/* these get called directly in cdl_add_connpt in fops bypass hack */ -extern int xbow_attach(vertex_hdl_t); -extern int pic_attach(vertex_hdl_t); - -/* - * cdl: Connection and Driver List - * - * We are not porting this to Linux. Devices are registered via - * the normal Linux PCI layer. This is a very simplified version - * of cdl that will allow us to register and call our very own - * IO Infrastructure Drivers e.g. pcibr. - */ - -#define MAX_SGI_IO_INFRA_DRVR 5 - -static struct cdl sgi_infrastructure_drivers[MAX_SGI_IO_INFRA_DRVR] = -{ - { PIC_WIDGET_PART_NUM_BUS0, PIC_WIDGET_MFGR_NUM, pic_attach /* &pcibr_fops */}, - { PIC_WIDGET_PART_NUM_BUS1, PIC_WIDGET_MFGR_NUM, pic_attach /* &pcibr_fops */}, - { XXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, - { XBOW_WIDGET_PART_NUM, XBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, - { PXBOW_WIDGET_PART_NUM, XXBOW_WIDGET_MFGR_NUM, xbow_attach /* &xbow_fops */}, -}; - -/* - * cdl_add_connpt: We found a device and it's connect point. Call the - * attach routine of that driver. - * - * May need support for pciba registration here ... - * - * This routine use to create /hw/.id/pci/.../.. that links to - * /hw/module/006c06/Pbrick/xtalk/15/pci/ .. do we still need - * it? The specified driver attach routine does not reference these - * vertices. - */ -int -cdl_add_connpt(int part_num, int mfg_num, - vertex_hdl_t connpt, int drv_flags) -{ - int i; - - /* - * Find the driver entry point and call the attach routine. - */ - for (i = 0; i < MAX_SGI_IO_INFRA_DRVR; i++) { - if ( (part_num == sgi_infrastructure_drivers[i].part_num) && - ( mfg_num == sgi_infrastructure_drivers[i].mfg_num) ) { - /* - * Call the device attach routines. - */ - if (sgi_infrastructure_drivers[i].attach) { - return(sgi_infrastructure_drivers[i].attach(connpt)); - } - } else { - continue; - } - } - - /* printk("WARNING: cdl_add_connpt: Driver not found for part_num 0x%x mfg_num 0x%x\n", part_num, mfg_num); */ - - return (0); -} diff --git a/arch/ia64/sn/io/drivers/Makefile b/arch/ia64/sn/io/drivers/Makefile deleted file mode 100644 index 9de74d252..000000000 --- a/arch/ia64/sn/io/drivers/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 io routines. - -obj-y += ioconfig_bus.o diff --git a/arch/ia64/sn/io/drivers/ioconfig_bus.c b/arch/ia64/sn/io/drivers/ioconfig_bus.c deleted file mode 100644 index a0a1eca21..000000000 --- a/arch/ia64/sn/io/drivers/ioconfig_bus.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -static struct ioconfig_parm parm; - -#ifdef IOCONFIG_BUS_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static u64 ioconfig_activated; -static char ioconfig_kernopts[128]; - -/* - * For debugging purpose .. hardcode a table .. - */ -struct ascii_moduleid *ioconfig_bus_table; - -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; - if (!ioconfig_bus_table) - return; - 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; - if (!temp) { - DBG("ioconfig_bus_table tabel empty\n"); - return; - } - 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. - */ -int -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 *curr; - char *line; - struct ascii_moduleid *moduleid; - - line = kmalloc(256, GFP_KERNEL); - name = kmalloc(125, GFP_KERNEL); - if (!line || !name) { - if (line) - kfree(line); - if (name) - kfree(name); - printk("build_moduleid_table(): Unabled to allocate memmory"); - return -ENOMEM; - } - - memset(line, 0,256); - memset(name, 0, 125); - moduleid = table; - curr = file_contents; - while (nextline(curr, &next, line)){ - - DBG("curr 0x%lx next 0x%lx\n", curr, next); - - temp = line; - /* - * Skip all leading Blank lines .. - */ - while (isspace(*temp)) - if (*temp != '\n') - temp++; - else - break; - - if (*temp == '\n') { - curr = next; - memset(line, 0, 256); - continue; - } - - /* - * Skip comment lines - */ - if (*temp == '#') { - curr = 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++; - curr = next; - memset(line, 0, 256); - } - - new_entry = free_entry; - kfree(line); - kfree(name); - - return 0; -} - -int -ioconfig_bus_init(void) -{ - - DBG("ioconfig_bus_init called.\n"); - - ioconfig_bus_table = kmalloc( 512, GFP_KERNEL ); - if (!ioconfig_bus_table) { - printk("ioconfig_bus_init : cannot allocate memory\n"); - return -1; - } - - 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"); - if ( build_moduleid_table((char *)ioconfig_kernopts, ioconfig_bus_table) < 0 ) - return -1; - (void) dump_ioconfig_table(); - } - return 0; -} - -void -ioconfig_bus_new_entries(void) -{ - int index; - 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; - if (!ioconfig_bus_table) { - printk("ioconfig_bus_table table is empty\n"); - return; - } - 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) -{ - /* - * Copy in the parameters. - */ - if (copy_from_user(&parm, (char *)arg, sizeof(struct ioconfig_parm))) - return -EFAULT; - parm.number = free_entry - new_entry; - parm.ioconfig_activated = ioconfig_activated; - if (copy_to_user((char *)arg, &parm, sizeof(struct ioconfig_parm))) - return -EFAULT; - - if (!ioconfig_bus_table) - return -EFAULT; - - if (copy_to_user((char *)parm.buffer, &ioconfig_bus_table[new_entry], sizeof(struct ascii_moduleid) * (free_entry - new_entry))) - return -EFAULT; - - 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 hwgfs has been initialized. - * - */ -int init_ioconfig_bus(void) -{ - ioconfig_bus_handle = hwgraph_register(hwgraph_root, ".ioconfig_bus", - 0, 0, - 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); diff --git a/arch/ia64/sn/io/hwgfs/Makefile b/arch/ia64/sn/io/hwgfs/Makefile deleted file mode 100644 index 9e6ef064d..000000000 --- a/arch/ia64/sn/io/hwgfs/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 io routines. - -obj-y += hcl.o labelcl.o hcl_util.o ramfs.o interface.o diff --git a/arch/ia64/sn/io/hwgfs/hcl.c b/arch/ia64/sn/io/hwgfs/hcl.c deleted file mode 100644 index 2c037144c..000000000 --- a/arch/ia64/sn/io/hwgfs/hcl.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * 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. - * - * hcl - SGI's Hardware Graph compatibility layer. - * - * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* needed for smp_lock.h :( */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define vertex_hdl_t hwgfs_handle_t - -vertex_hdl_t hwgraph_root; -vertex_hdl_t linux_busnum; -extern int pci_bus_cvlink_init(void); -unsigned long hwgraph_debug_mask; - -/* - * init_hcl() - Boot time initialization. - * - */ -int __init init_hcl(void) -{ - extern void string_table_init(struct string_table *); - extern struct string_table label_string_table; - extern int init_ioconfig_bus(void); - extern int init_hwgfs_fs(void); - int rv = 0; - - init_hwgfs_fs(); - - /* - * Create the hwgraph_root. - */ - rv = hwgraph_path_add(NULL, EDGE_LBL_HW, &hwgraph_root); - if (rv) { - printk("init_hcl: Failed to create hwgraph_root.\n"); - return -1; - } - - /* - * Initialize the HCL string table. - */ - - string_table_init(&label_string_table); - - /* - * Create the directory that links Linux bus numbers to our Xwidget. - */ - rv = hwgraph_path_add(hwgraph_root, EDGE_LBL_LINUX_BUS, &linux_busnum); - if (linux_busnum == NULL) { - printk("HCL: Unable to create %s\n", EDGE_LBL_LINUX_BUS); - return -1; - } - - if (pci_bus_cvlink_init() < 0 ) { - printk("init_hcl: Failed to create pcibus cvlink.\n"); - return -1; - } - - /* - * Persistent Naming. - */ - init_ioconfig_bus(); - - return 0; -} - -/* - * Get device specific "fast information". - * - */ -arbitrary_info_t -hwgraph_fastinfo_get(vertex_hdl_t de) -{ - arbitrary_info_t fastinfo; - int rv; - - if (!de) { - printk(KERN_WARNING "HCL: hwgraph_fastinfo_get handle given is NULL.\n"); - dump_stack(); - return(-1); - } - - rv = labelcl_info_get_IDX(de, HWGRAPH_FASTINFO, &fastinfo); - if (rv == 0) - return(fastinfo); - - return(0); -} - - -/* - * hwgraph_connectpt_get: Returns the entry's connect point. - * - */ -vertex_hdl_t -hwgraph_connectpt_get(vertex_hdl_t de) -{ - int rv; - arbitrary_info_t info; - vertex_hdl_t connect; - - rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); - if (rv != 0) { - return(NULL); - } - - connect = (vertex_hdl_t)info; - return(connect); - -} - - -/* - * hwgraph_mk_dir - Creates a directory entry. - */ -vertex_hdl_t -hwgraph_mk_dir(vertex_hdl_t de, const char *name, - unsigned int namelen, void *info) -{ - - int rv; - labelcl_info_t *labelcl_info = NULL; - vertex_hdl_t new_handle = NULL; - vertex_hdl_t parent = NULL; - - /* - * Create the device info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(NULL); - - /* - * Create an entry. - */ - new_handle = hwgfs_mk_dir(de, name, (void *)labelcl_info); - if (!new_handle) { - labelcl_info_destroy(labelcl_info); - return(NULL); - } - - /* - * Get the parent handle. - */ - parent = hwgfs_get_parent (new_handle); - - /* - * To provide the same semantics as the hwgraph, set the connect point. - */ - rv = hwgraph_connectpt_set(new_handle, parent); - if (!rv) { - /* - * We need to clean up! - */ - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); - - return(new_handle); - -} - -/* - * hwgraph_path_add - Create a directory node with the given path starting - * from the given fromv. - */ -int -hwgraph_path_add(vertex_hdl_t fromv, - char *path, - vertex_hdl_t *new_de) -{ - - unsigned int namelen = strlen(path); - int rv; - - /* - * We need to handle the case when fromv is NULL .. - * in this case we need to create the path from the - * hwgraph root! - */ - if (fromv == NULL) - fromv = hwgraph_root; - - /* - * check the entry doesn't already exist, if it does - * then we simply want new_de to point to it (otherwise - * we'll overwrite the existing labelcl_info struct) - */ - rv = hwgraph_edge_get(fromv, path, new_de); - if (rv) { /* couldn't find entry so we create it */ - *new_de = hwgraph_mk_dir(fromv, path, namelen, NULL); - if (new_de == NULL) - return(-1); - else - return(0); - } - else - return(0); - -} - -/* - * hwgraph_register - Creates a special device file. - * - */ -vertex_hdl_t -hwgraph_register(vertex_hdl_t de, const char *name, - unsigned int namelen, unsigned int flags, - unsigned int major, unsigned int minor, - umode_t mode, uid_t uid, gid_t gid, - struct file_operations *fops, - void *info) -{ - - vertex_hdl_t new_handle = NULL; - - /* - * Create an entry. - */ - new_handle = hwgfs_register(de, name, flags, major, - minor, mode, fops, info); - - return(new_handle); - -} - - -/* - * hwgraph_mk_symlink - Create a symbolic link. - */ -int -hwgraph_mk_symlink(vertex_hdl_t de, const char *name, unsigned int namelen, - unsigned int flags, const char *link, unsigned int linklen, - vertex_hdl_t *handle, void *info) -{ - - void *labelcl_info = NULL; - int status = 0; - vertex_hdl_t new_handle = NULL; - - /* - * Create the labelcl info structure for hwgraph compatiblity support. - */ - labelcl_info = labelcl_info_create(); - if (!labelcl_info) - return(-1); - - /* - * Create a symbolic link. - */ - status = hwgfs_mk_symlink(de, name, flags, link, - &new_handle, labelcl_info); - if ( (!new_handle) || (!status) ){ - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - return(-1); - } - - /* - * If the caller provides a private data pointer, save it in the - * labelcl info structure(fastinfo). This can be retrieved via - * hwgraph_fastinfo_get() - */ - if (info) - hwgraph_fastinfo_set(new_handle, (arbitrary_info_t)info); - - *handle = new_handle; - return(0); - -} - -/* - * hwgraph_vertex_destroy - Destroy the entry - */ -int -hwgraph_vertex_destroy(vertex_hdl_t de) -{ - - void *labelcl_info = NULL; - - labelcl_info = hwgfs_get_info(de); - hwgfs_unregister(de); - - if (labelcl_info) - labelcl_info_destroy((labelcl_info_t *)labelcl_info); - - return(0); -} - -int -hwgraph_edge_add(vertex_hdl_t from, vertex_hdl_t to, char *name) -{ - - char *path, *link; - char *s1; - char *index; - vertex_hdl_t handle = NULL; - int rv; - int i, count; - - path = kmalloc(1024, GFP_KERNEL); - if (!path) - return -ENOMEM; - memset((char *)path, 0x0, 1024); - link = kmalloc(1024, GFP_KERNEL); - if (!link) { - kfree(path); - return -ENOMEM; - } - memset((char *)link, 0x0, 1024); - - i = hwgfs_generate_path (from, path, 1024); - s1 = (char *)path; - count = 0; - while (1) { - index = strstr (s1, "/"); - if (index) { - count++; - s1 = ++index; - } else { - count++; - break; - } - } - - for (i = 0; i < count; i++) { - strcat((char *)link,"../"); - } - - memset(path, 0x0, 1024); - i = hwgfs_generate_path (to, path, 1024); - strcat((char *)link, (char *)path); - - /* - * Otherwise, just create a symlink to the vertex. - * In this case the vertex was previous created with a REAL pathname. - */ - rv = hwgfs_mk_symlink (from, (const char *)name, - 0, link, - &handle, NULL); - kfree(path); - kfree(link); - - return(rv); - - -} - -/* ARGSUSED */ -int -hwgraph_edge_get(vertex_hdl_t from, char *name, vertex_hdl_t *toptr) -{ - - vertex_hdl_t target_handle = NULL; - - if (name == NULL) - return(-1); - - if (toptr == NULL) - return(-1); - - /* - * If the name is "." just return the current entry handle. - */ - if (!strcmp(name, HWGRAPH_EDGELBL_DOT)) { - if (toptr) { - *toptr = from; - } - } else if (!strcmp(name, HWGRAPH_EDGELBL_DOTDOT)) { - /* - * Hmmm .. should we return the connect point or parent .. - * see in hwgraph, the concept of parent is the connectpt! - * - * Maybe we should see whether the connectpt is set .. if - * not just return the parent! - */ - target_handle = hwgraph_connectpt_get(from); - if (target_handle) { - /* - * Just return the connect point. - */ - *toptr = target_handle; - return(0); - } - target_handle = hwgfs_get_parent(from); - *toptr = target_handle; - - } else { - target_handle = hwgfs_find_handle (from, name, 0, 0, - 0, 1); /* Yes traverse symbolic links */ - } - - if (target_handle == NULL) - return(-1); - else - *toptr = target_handle; - - return(0); -} - -/* - * hwgraph_info_add_LBL - Adds a new label for the device. Mark the info_desc - * of the label as INFO_DESC_PRIVATE and store the info in the label. - */ -/* ARGSUSED */ -int -hwgraph_info_add_LBL( vertex_hdl_t de, - char *name, - arbitrary_info_t info) -{ - return(labelcl_info_add_LBL(de, name, INFO_DESC_PRIVATE, info)); -} - -/* - * hwgraph_info_remove_LBL - Remove the label entry for the device. - */ -/* ARGSUSED */ -int -hwgraph_info_remove_LBL( vertex_hdl_t de, - char *name, - arbitrary_info_t *old_info) -{ - return(labelcl_info_remove_LBL(de, name, NULL, old_info)); -} - -/* - * hwgraph_info_replace_LBL - replaces an existing label with - * a new label info value. - */ -/* ARGSUSED */ -int -hwgraph_info_replace_LBL( vertex_hdl_t de, - char *name, - arbitrary_info_t info, - arbitrary_info_t *old_info) -{ - return(labelcl_info_replace_LBL(de, name, - INFO_DESC_PRIVATE, info, - NULL, old_info)); -} -/* - * hwgraph_info_get_LBL - Get and return the info value in the label of the - * device. - */ -/* ARGSUSED */ -int -hwgraph_info_get_LBL(vertex_hdl_t de, - char *name, - arbitrary_info_t *infop) -{ - return(labelcl_info_get_LBL(de, name, NULL, infop)); -} - -/* - * hwgraph_info_get_exported_LBL - Retrieve the info_desc and info pointer - * of the given label for the device. The weird thing is that the label - * that matches the name is return irrespective of the info_desc value! - * Do not understand why the word "exported" is used! - */ -/* ARGSUSED */ -int -hwgraph_info_get_exported_LBL(vertex_hdl_t de, - char *name, - int *export_info, - arbitrary_info_t *infop) -{ - int rc; - arb_info_desc_t info_desc; - - rc = labelcl_info_get_LBL(de, name, &info_desc, infop); - if (rc == 0) - *export_info = (int)info_desc; - - return(rc); -} - -/* - * hwgraph_info_get_next_LBL - Returns the next label info given the - * current label entry in place. - * - * Once again this has no locking or reference count for protection. - * - */ -/* ARGSUSED */ -int -hwgraph_info_get_next_LBL(vertex_hdl_t de, - char *buf, - arbitrary_info_t *infop, - labelcl_info_place_t *place) -{ - return(labelcl_info_get_next_LBL(de, buf, NULL, infop, place)); -} - -/* - * hwgraph_info_export_LBL - Retrieve the specified label entry and modify - * the info_desc field with the given value in nbytes. - */ -/* ARGSUSED */ -int -hwgraph_info_export_LBL(vertex_hdl_t de, char *name, int nbytes) -{ - arbitrary_info_t info; - int rc; - - if (nbytes == 0) - nbytes = INFO_DESC_EXPORT; - - if (nbytes < 0) - return(-1); - - rc = labelcl_info_get_LBL(de, name, NULL, &info); - if (rc != 0) - return(rc); - - rc = labelcl_info_replace_LBL(de, name, - nbytes, info, NULL, NULL); - - return(rc); -} - -/* - * hwgraph_info_unexport_LBL - Retrieve the given label entry and change the - * label info_descr filed to INFO_DESC_PRIVATE. - */ -/* ARGSUSED */ -int -hwgraph_info_unexport_LBL(vertex_hdl_t de, char *name) -{ - arbitrary_info_t info; - int rc; - - rc = labelcl_info_get_LBL(de, name, NULL, &info); - if (rc != 0) - return(rc); - - rc = labelcl_info_replace_LBL(de, name, - INFO_DESC_PRIVATE, info, NULL, NULL); - - return(rc); -} - -/* - * hwgraph_traverse - Find and return the handle starting from de. - * - */ -graph_error_t -hwgraph_traverse(vertex_hdl_t de, char *path, vertex_hdl_t *found) -{ - /* - * get the directory entry (path should end in a directory) - */ - - *found = hwgfs_find_handle(de, /* start dir */ - path, /* path */ - 0, /* major */ - 0, /* minor */ - 0, /* char | block */ - 1); /* traverse symlinks */ - if (*found == NULL) - return(GRAPH_NOT_FOUND); - else - return(GRAPH_SUCCESS); -} - -/* - * Find the canonical name for a given vertex by walking back through - * connectpt's until we hit the hwgraph root vertex (or until we run - * out of buffer space or until something goes wrong). - * - * COMPATIBILITY FUNCTIONALITY - * Walks back through 'parents', not necessarily the same as connectpts. - * - * Need to resolve the fact that does not return the path from - * "/" but rather it just stops right before /dev .. - */ -int -hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, unsigned int buflen) -{ - char *locbuf; - int pos; - - if (buflen < 1) - return(-1); /* XXX should be GRAPH_BAD_PARAM ? */ - - locbuf = kmalloc(buflen, GFP_KERNEL); - - pos = hwgfs_generate_path(vhdl, locbuf, buflen); - if (pos < 0) { - kfree(locbuf); - return pos; - } - - strcpy(buf, &locbuf[pos]); - kfree(locbuf); - return 0; -} - -/* -** vertex_to_name converts a vertex into a canonical name by walking -** back through connect points until we hit the hwgraph root (or until -** we run out of buffer space). -** -** Usually returns a pointer to the original buffer, filled in as -** appropriate. If the buffer is too small to hold the entire name, -** or if anything goes wrong while determining the name, vertex_to_name -** returns "UnknownDevice". -*/ - -#define DEVNAME_UNKNOWN "UnknownDevice" - -char * -vertex_to_name(vertex_hdl_t vhdl, char *buf, unsigned int buflen) -{ - if (hwgraph_vertex_name_get(vhdl, buf, buflen) == GRAPH_SUCCESS) - return(buf); - else - return(DEVNAME_UNKNOWN); -} - - -void -hwgraph_debug(char *file, const char * function, int line, vertex_hdl_t vhdl1, vertex_hdl_t vhdl2, char *format, ...) -{ - - int pos; - char *hwpath; - va_list ap; - - if ( !hwgraph_debug_mask ) - return; - - hwpath = kmalloc(MAXDEVNAME, GFP_KERNEL); - if (!hwpath) { - printk("HWGRAPH_DEBUG kmalloc fails at %d ", __LINE__); - return; - } - - printk("HWGRAPH_DEBUG %s %s %d : ", file, function, line); - - if (vhdl1){ - memset(hwpath, 0, MAXDEVNAME); - pos = hwgfs_generate_path(vhdl1, hwpath, MAXDEVNAME); - printk("vhdl1 = %s : ", &hwpath[pos]); - } - - if (vhdl2){ - memset(hwpath, 0, MAXDEVNAME); - pos = hwgfs_generate_path(vhdl2, hwpath, MAXDEVNAME); - printk("vhdl2 = %s :", &hwpath[pos]); - } - - memset(hwpath, 0, MAXDEVNAME); - va_start(ap, format); - vsnprintf(hwpath, 500, format, ap); - va_end(ap); - hwpath[MAXDEVNAME -1] = (char)0; /* Just in case. */ - printk(" %s", hwpath); - kfree(hwpath); -} - -EXPORT_SYMBOL(hwgraph_mk_dir); -EXPORT_SYMBOL(hwgraph_path_add); -EXPORT_SYMBOL(hwgraph_register); -EXPORT_SYMBOL(hwgraph_vertex_destroy); -EXPORT_SYMBOL(hwgraph_fastinfo_get); -EXPORT_SYMBOL(hwgraph_connectpt_get); -EXPORT_SYMBOL(hwgraph_info_add_LBL); -EXPORT_SYMBOL(hwgraph_info_remove_LBL); -EXPORT_SYMBOL(hwgraph_info_replace_LBL); -EXPORT_SYMBOL(hwgraph_info_get_LBL); -EXPORT_SYMBOL(hwgraph_info_get_exported_LBL); -EXPORT_SYMBOL(hwgraph_info_get_next_LBL); -EXPORT_SYMBOL(hwgraph_info_export_LBL); -EXPORT_SYMBOL(hwgraph_info_unexport_LBL); -EXPORT_SYMBOL(hwgraph_traverse); -EXPORT_SYMBOL(hwgraph_vertex_name_get); diff --git a/arch/ia64/sn/io/hwgfs/hcl_util.c b/arch/ia64/sn/io/hwgfs/hcl_util.c deleted file mode 100644 index d6aa26c9a..000000000 --- a/arch/ia64/sn/io/hwgfs/hcl_util.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static vertex_hdl_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE; -extern vertex_hdl_t hwgraph_root; -static vertex_hdl_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE; -extern int maxcpus; - -void -mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid) -{ - char cpuid_buffer[10]; - - if (cpuid == CPU_NONE) - return; - - if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) { - (void)hwgraph_path_add( hwgraph_root, - EDGE_LBL_CPUNUM, - &hwgraph_all_cpuids); - } - - sprintf(cpuid_buffer, "%ld", cpuid); - (void)hwgraph_edge_add( hwgraph_all_cpuids, vhdl, cpuid_buffer); -} - -/* -** Return the "master" for a given vertex. A master vertex is a -** controller or adapter or other piece of hardware that the given -** vertex passes through on the way to the rest of the system. -*/ -vertex_hdl_t -device_master_get(vertex_hdl_t vhdl) -{ - graph_error_t rc; - vertex_hdl_t master; - - rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master); - if (rc == GRAPH_SUCCESS) - return(master); - else - return(GRAPH_VERTEX_NONE); -} - -/* -** Set the master for a given vertex. -** Returns 0 on success, non-0 indicates failure -*/ -int -device_master_set(vertex_hdl_t vhdl, vertex_hdl_t master) -{ - graph_error_t rc; - - rc = hwgraph_edge_add(vhdl, master, EDGE_LBL_MASTER); - return(rc != GRAPH_SUCCESS); -} - - -/* -** Return the compact node id of the node that ultimately "owns" the specified -** vertex. In order to do this, we walk back through masters and connect points -** until we reach a vertex that represents a node. -*/ -cnodeid_t -master_node_get(vertex_hdl_t vhdl) -{ - cnodeid_t cnodeid; - vertex_hdl_t master; - - for (;;) { - cnodeid = nodevertex_to_cnodeid(vhdl); - if (cnodeid != CNODEID_NONE) - return(cnodeid); - - master = device_master_get(vhdl); - - /* Check for exceptional cases */ - if (master == vhdl) { - /* Since we got a reference to the "master" thru - * device_master_get() we should decrement - * its reference count by 1 - */ - return(CNODEID_NONE); - } - - if (master == GRAPH_VERTEX_NONE) { - master = hwgraph_connectpt_get(vhdl); - if ((master == GRAPH_VERTEX_NONE) || - (master == vhdl)) { - return(CNODEID_NONE); - } - } - - vhdl = master; - } -} - - -/* -** If the specified device represents a node, return its -** compact node ID; otherwise, return CNODEID_NONE. -*/ -cnodeid_t -nodevertex_to_cnodeid(vertex_hdl_t vhdl) -{ - int rv = 0; - arbitrary_info_t cnodeid = CNODEID_NONE; - - rv = labelcl_info_get_LBL(vhdl, INFO_LBL_CNODEID, NULL, &cnodeid); - - return((cnodeid_t)cnodeid); -} - -void -mark_nodevertex_as_node(vertex_hdl_t vhdl, cnodeid_t cnodeid) -{ - if (cnodeid == CNODEID_NONE) - return; - - cnodeid_to_vertex(cnodeid) = vhdl; - labelcl_info_add_LBL(vhdl, INFO_LBL_CNODEID, INFO_DESC_EXPORT, - (arbitrary_info_t)cnodeid); - - { - char cnodeid_buffer[10]; - - if (hwgraph_all_cnodes == GRAPH_VERTEX_NONE) { - (void)hwgraph_path_add( hwgraph_root, - EDGE_LBL_NODENUM, - &hwgraph_all_cnodes); - } - - sprintf(cnodeid_buffer, "%d", cnodeid); - (void)hwgraph_edge_add( hwgraph_all_cnodes, - vhdl, - cnodeid_buffer); - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hwgraph_all_cnodes, NULL, "Creating path vhdl1\n"); - } -} - -/* -** dev_to_name converts a vertex_hdl_t into a canonical name. If the vertex_hdl_t -** represents a vertex in the hardware graph, it is converted in the -** normal way for vertices. If the vertex_hdl_t is an old vertex_hdl_t (one which -** does not represent a hwgraph vertex), we synthesize a name based -** on major/minor number. -** -** Usually returns a pointer to the original buffer, filled in as -** appropriate. If the buffer is too small to hold the entire name, -** or if anything goes wrong while determining the name, dev_to_name -** returns "UnknownDevice". -*/ -char * -dev_to_name(vertex_hdl_t dev, char *buf, uint buflen) -{ - return(vertex_to_name(dev, buf, buflen)); -} - diff --git a/arch/ia64/sn/io/hwgfs/interface.c b/arch/ia64/sn/io/hwgfs/interface.c deleted file mode 100644 index caac7f067..000000000 --- a/arch/ia64/sn/io/hwgfs/interface.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * 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. - * - * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. - * - * Portions based on Adam Richter's smalldevfs and thus - * Copyright 2002-2003 Yggdrasil Computing, Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -extern struct vfsmount *hwgfs_vfsmount; - -static int -walk_parents_mkdir( - const char **path, - struct nameidata *nd, - int is_dir) -{ - char *slash; - char buf[strlen(*path)+1]; - int error; - - while ((slash = strchr(*path, '/')) != NULL) { - int len = slash - *path; - memcpy(buf, *path, len); - buf[len] = '\0'; - - error = path_walk(buf, nd); - if (unlikely(error)) - return error; - - nd->dentry = lookup_create(nd, is_dir); - nd->flags |= LOOKUP_PARENT; - if (unlikely(IS_ERR(nd->dentry))) - return PTR_ERR(nd->dentry); - - if (!nd->dentry->d_inode) - error = vfs_mkdir(nd->dentry->d_parent->d_inode, - nd->dentry, 0755); - - up(&nd->dentry->d_parent->d_inode->i_sem); - if (unlikely(error)) - return error; - - *path += len + 1; - } - - return 0; -} - -/* On success, returns with parent_inode->i_sem taken. */ -static int -hwgfs_decode( - hwgfs_handle_t dir, - const char *name, - int is_dir, - struct inode **parent_inode, - struct dentry **dentry) -{ - struct nameidata nd; - int error; - - if (!dir) - dir = hwgfs_vfsmount->mnt_sb->s_root; - - memset(&nd, 0, sizeof(nd)); - nd.flags = LOOKUP_PARENT; - nd.mnt = mntget(hwgfs_vfsmount); - nd.dentry = dget(dir); - - error = walk_parents_mkdir(&name, &nd, is_dir); - if (unlikely(error)) - return error; - - error = path_walk(name, &nd); - if (unlikely(error)) - return error; - - *dentry = lookup_create(&nd, is_dir); - - if (unlikely(IS_ERR(*dentry))) - return PTR_ERR(*dentry); - *parent_inode = (*dentry)->d_parent->d_inode; - return 0; -} - -static int -path_len( - struct dentry *de, - struct dentry *root) -{ - int len = 0; - - while (de != root) { - len += de->d_name.len + 1; /* count the '/' */ - de = de->d_parent; - } - return len; /* -1 because we omit the leading '/', - +1 because we include trailing '\0' */ -} - -int -hwgfs_generate_path( - hwgfs_handle_t de, - char *path, - int buflen) -{ - struct dentry *hwgfs_root; - int len; - char *path_orig = path; - - if (unlikely(de == NULL)) - return -EINVAL; - - hwgfs_root = hwgfs_vfsmount->mnt_sb->s_root; - if (unlikely(de == hwgfs_root)) - return -EINVAL; - - spin_lock(&dcache_lock); - len = path_len(de, hwgfs_root); - if (len > buflen) { - spin_unlock(&dcache_lock); - return -ENAMETOOLONG; - } - - path += len - 1; - *path = '\0'; - - for (;;) { - path -= de->d_name.len; - memcpy(path, de->d_name.name, de->d_name.len); - de = de->d_parent; - if (de == hwgfs_root) - break; - *(--path) = '/'; - } - - spin_unlock(&dcache_lock); - BUG_ON(path != path_orig); - return 0; -} - -hwgfs_handle_t -hwgfs_register( - hwgfs_handle_t dir, - const char *name, - unsigned int flags, - unsigned int major, - unsigned int minor, - umode_t mode, - void *ops, - void *info) -{ - dev_t devnum = MKDEV(major, minor); - struct inode *parent_inode; - struct dentry *dentry; - int error; - - error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); - if (likely(!error)) { - error = vfs_mknod(parent_inode, dentry, mode, devnum); - if (likely(!error)) { - /* - * Do this inside parents i_sem to avoid racing - * with lookups. - */ - if (S_ISCHR(mode)) - dentry->d_inode->i_fop = ops; - dentry->d_fsdata = info; - up(&parent_inode->i_sem); - } else { - up(&parent_inode->i_sem); - dput(dentry); - dentry = NULL; - } - } - - return dentry; -} - -int -hwgfs_mk_symlink( - hwgfs_handle_t dir, - const char *name, - unsigned int flags, - const char *link, - hwgfs_handle_t *handle, - void *info) -{ - struct inode *parent_inode; - struct dentry *dentry; - int error; - - error = hwgfs_decode(dir, name, 0, &parent_inode, &dentry); - if (likely(!error)) { - error = vfs_symlink(parent_inode, dentry, link, S_IALLUGO); - dentry->d_fsdata = info; - if (handle) - *handle = dentry; - up(&parent_inode->i_sem); - /* dput(dentry); */ - } - return error; -} - -hwgfs_handle_t -hwgfs_mk_dir( - hwgfs_handle_t dir, - const char *name, - void *info) -{ - struct inode *parent_inode; - struct dentry *dentry; - int error; - - error = hwgfs_decode(dir, name, 1, &parent_inode, &dentry); - if (likely(!error)) { - error = vfs_mkdir(parent_inode, dentry, 0755); - up(&parent_inode->i_sem); - - if (unlikely(error)) { - dput(dentry); - dentry = NULL; - } else { - dentry->d_fsdata = info; - } - } - return dentry; -} - -void -hwgfs_unregister( - hwgfs_handle_t de) -{ - struct inode *parent_inode = de->d_parent->d_inode; - - if (S_ISDIR(de->d_inode->i_mode)) - vfs_rmdir(parent_inode, de); - else - vfs_unlink(parent_inode, de); -} - -/* XXX: this function is utterly bogus. Every use of it is racy and the - prototype is stupid. You have been warned. --hch. */ -hwgfs_handle_t -hwgfs_find_handle( - hwgfs_handle_t base, - const char *name, - unsigned int major, /* IGNORED */ - unsigned int minor, /* IGNORED */ - char type, /* IGNORED */ - int traverse_symlinks) -{ - struct dentry *dentry = NULL; - struct nameidata nd; - int error; - - BUG_ON(*name=='/'); - - memset(&nd, 0, sizeof(nd)); - - nd.mnt = mntget(hwgfs_vfsmount); - nd.dentry = dget(base ? base : hwgfs_vfsmount->mnt_sb->s_root); - nd.flags = (traverse_symlinks ? LOOKUP_FOLLOW : 0); - - error = path_walk(name, &nd); - if (likely(!error)) { - dentry = nd.dentry; - path_release(&nd); /* stale data from here! */ - } - - return dentry; -} - -hwgfs_handle_t -hwgfs_get_parent( - hwgfs_handle_t de) -{ - struct dentry *parent; - - spin_lock(&de->d_lock); - parent = de->d_parent; - spin_unlock(&de->d_lock); - - return parent; -} - -int -hwgfs_set_info( - hwgfs_handle_t de, - void *info) -{ - if (unlikely(de == NULL)) - return -EINVAL; - de->d_fsdata = info; - return 0; -} - -void * -hwgfs_get_info( - hwgfs_handle_t de) -{ - return de->d_fsdata; -} - -EXPORT_SYMBOL(hwgfs_generate_path); -EXPORT_SYMBOL(hwgfs_register); -EXPORT_SYMBOL(hwgfs_unregister); -EXPORT_SYMBOL(hwgfs_mk_symlink); -EXPORT_SYMBOL(hwgfs_mk_dir); -EXPORT_SYMBOL(hwgfs_find_handle); -EXPORT_SYMBOL(hwgfs_get_parent); -EXPORT_SYMBOL(hwgfs_set_info); -EXPORT_SYMBOL(hwgfs_get_info); diff --git a/arch/ia64/sn/io/hwgfs/labelcl.c b/arch/ia64/sn/io/hwgfs/labelcl.c deleted file mode 100644 index 536442a8b..000000000 --- a/arch/ia64/sn/io/hwgfs/labelcl.c +++ /dev/null @@ -1,656 +0,0 @@ -/* labelcl - SGI's Hwgraph Compatibility Layer. - * - * 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. - * - * Copyright (c) 2001-2003 Silicon Graphics, Inc. All rights reserved. -*/ - -#include -#include -#include -#include -#include -#include /* needed for smp_lock.h :( */ -#include -#include -#include -#include -#include - -/* -** Very simple and dumb string table that supports only find/insert. -** In practice, if this table gets too large, we may need a more -** efficient data structure. Also note that currently there is no -** way to delete an item once it's added. Therefore, name collision -** will return an error. -*/ - -struct string_table label_string_table; - - - -/* - * string_table_init - Initialize the given string table. - */ -void -string_table_init(struct string_table *string_table) -{ - string_table->string_table_head = NULL; - string_table->string_table_generation = 0; - - /* - * We nedd to initialize locks here! - */ - - return; -} - - -/* - * string_table_destroy - Destroy the given string table. - */ -void -string_table_destroy(struct string_table *string_table) -{ - struct string_table_item *item, *next_item; - - item = string_table->string_table_head; - while (item) { - next_item = item->next; - - STRTBL_FREE(item); - item = next_item; - } - - /* - * We need to destroy whatever lock we have here - */ - - return; -} - - - -/* - * string_table_insert - Insert an entry in the string table .. duplicate - * names are not allowed. - */ -char * -string_table_insert(struct string_table *string_table, char *name) -{ - struct string_table_item *item, *new_item = NULL, *last_item = NULL; - -again: - /* - * Need to lock the table .. - */ - item = string_table->string_table_head; - last_item = NULL; - - while (item) { - if (!strcmp(item->string, name)) { - /* - * If we allocated space for the string and the found that - * someone else already entered it into the string table, - * free the space we just allocated. - */ - if (new_item) - STRTBL_FREE(new_item); - - - /* - * Search optimization: move the found item to the head - * of the list. - */ - if (last_item != NULL) { - last_item->next = item->next; - item->next = string_table->string_table_head; - string_table->string_table_head = item; - } - goto out; - } - last_item = item; - item=item->next; - } - - /* - * name was not found, so add it to the string table. - */ - if (new_item == NULL) { - long old_generation = string_table->string_table_generation; - - new_item = STRTBL_ALLOC(strlen(name)); - - strcpy(new_item->string, name); - - /* - * While we allocated memory for the new string, someone else - * changed the string table. - */ - if (old_generation != string_table->string_table_generation) { - goto again; - } - } else { - /* At this we only have the string table lock in access mode. - * Promote the access lock to an update lock for the string - * table insertion below. - */ - long old_generation = - string_table->string_table_generation; - - /* - * After we did the unlock and wer waiting for update - * lock someone could have potentially updated - * the string table. Check the generation number - * for this case. If it is the case we have to - * try all over again. - */ - if (old_generation != - string_table->string_table_generation) { - goto again; - } - } - - /* - * At this point, we're committed to adding new_item to the string table. - */ - new_item->next = string_table->string_table_head; - item = string_table->string_table_head = new_item; - string_table->string_table_generation++; - -out: - /* - * Need to unlock here. - */ - return(item->string); -} - -/* - * labelcl_info_create - Creates the data structure that will hold the - * device private information asscoiated with a entry. - * The pointer to this structure is what gets stored in the - * (void * info). - */ -labelcl_info_t * -labelcl_info_create() -{ - - labelcl_info_t *new = NULL; - - /* Initial allocation does not include any area for labels */ - if ( ( new = (labelcl_info_t *)kmalloc (sizeof(labelcl_info_t), GFP_KERNEL) ) == NULL ) - return NULL; - - memset (new, 0, sizeof(labelcl_info_t)); - new->hwcl_magic = LABELCL_MAGIC; - return( new); - -} - -/* - * labelcl_info_destroy - Frees the data structure that holds the - * device private information asscoiated with a entry. This - * data structure was created by device_info_create(). - * - * The caller is responsible for nulling the (void *info) in the - * corresponding entry. - */ -int -labelcl_info_destroy(labelcl_info_t *labelcl_info) -{ - - if (labelcl_info == NULL) - return(0); - - /* Free the label list */ - if (labelcl_info->label_list) - kfree(labelcl_info->label_list); - - /* Now free the label info area */ - labelcl_info->hwcl_magic = 0; - kfree(labelcl_info); - - return(0); -} - -/* - * labelcl_info_add_LBL - Adds a new label entry in the labelcl info - * structure. - * - * Error is returned if we find another label with the same name. - */ -int -labelcl_info_add_LBL(vertex_hdl_t de, - char *info_name, - arb_info_desc_t info_desc, - arbitrary_info_t info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - int new_label_list_size; - label_info_t *old_label_list, *new_label_list = NULL; - char *name; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = hwgfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if (info_name == NULL) - return(-1); - - if (strlen(info_name) >= LABEL_LENGTH_MAX) - return(-1); - - name = string_table_insert(&label_string_table, info_name); - - num_labels = labelcl_info->num_labels; - new_label_list_size = sizeof(label_info_t) * (num_labels+1); - - /* - * Create a new label info area. - */ - if (new_label_list_size != 0) { - new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); - - if (new_label_list == NULL) - return(-1); - } - - /* - * At this point, we are committed to adding the labelled info, - * if there isn't already information there with the same name. - */ - old_label_list = labelcl_info->label_list; - - /* - * Look for matching info name. - */ - for (i=0; inum_labels = num_labels+1; - labelcl_info->label_list = new_label_list; - - if (old_label_list != NULL) - kfree(old_label_list); - - return(0); -} - -/* - * labelcl_info_remove_LBL - Remove a label entry. - */ -int -labelcl_info_remove_LBL(vertex_hdl_t de, - char *info_name, - arb_info_desc_t *info_desc, - arbitrary_info_t *info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - int new_label_list_size; - label_info_t *old_label_list, *new_label_list = NULL; - arb_info_desc_t label_desc_found; - arbitrary_info_t label_info_found; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = hwgfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - /* - * Create a new info area. - */ - new_label_list_size = sizeof(label_info_t) * (num_labels-1); - if (new_label_list_size) { - new_label_list = (label_info_t *) kmalloc(new_label_list_size, GFP_KERNEL); - if (new_label_list == NULL) - return(-1); - } - - /* - * At this point, we are committed to removing the labelled info, - * if it still exists. - */ - old_label_list = labelcl_info->label_list; - - /* - * Find matching info name. - */ - for (i=0; inum_labels = num_labels+1; - labelcl_info->label_list = new_label_list; - - kfree(old_label_list); - - if (info != NULL) - *info = label_info_found; - - if (info_desc != NULL) - *info_desc = label_desc_found; - - return(0); -} - - -/* - * labelcl_info_replace_LBL - Replace an existing label entry with the - * given new information. - * - * Label entry must exist. - */ -int -labelcl_info_replace_LBL(vertex_hdl_t de, - char *info_name, - arb_info_desc_t info_desc, - arbitrary_info_t info, - arb_info_desc_t *old_info_desc, - arbitrary_info_t *old_info) -{ - labelcl_info_t *labelcl_info = NULL; - int num_labels; - label_info_t *label_list; - int i; - - if (de == NULL) - return(-1); - - labelcl_info = hwgfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - if (info_name == NULL) - return(-1); - - label_list = labelcl_info->label_list; - - /* - * Verify that information under info_name already exists. - */ - for (i=0; ihwcl_magic != LABELCL_MAGIC) - return(-1); - - num_labels = labelcl_info->num_labels; - if (num_labels == 0) { - return(-1); - } - - label_list = labelcl_info->label_list; - - /* - * Find information under info_name. - */ - for (i=0; ihwcl_magic != LABELCL_MAGIC) - return(-1); - - which_info = *placeptr; - - if (which_info >= labelcl_info->num_labels) { - return(-1); - } - - label_list = (label_info_t *) labelcl_info->label_list; - - if (buffer != NULL) - strcpy(buffer, label_list[which_info].name); - - if (infop) - *infop = label_list[which_info].info; - - if (info_descp) - *info_descp = label_list[which_info].desc; - - *placeptr = which_info + 1; - - return(0); -} - - -int -labelcl_info_replace_IDX(vertex_hdl_t de, - int index, - arbitrary_info_t info, - arbitrary_info_t *old_info) -{ - arbitrary_info_t *info_list_IDX; - labelcl_info_t *labelcl_info = NULL; - - if (de == NULL) { - printk(KERN_ALERT "labelcl: NULL handle given.\n"); - return(-1); - } - - labelcl_info = hwgfs_get_info(de); - if (labelcl_info == NULL) { - printk(KERN_ALERT "labelcl: Entry %p does not have info pointer.\n", (void *)de); - return(-1); - } - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) - return(-1); - - /* - * Replace information at the appropriate index in this vertex with - * the new info. - */ - info_list_IDX = labelcl_info->IDX_list; - if (old_info != NULL) - *old_info = info_list_IDX[index]; - info_list_IDX[index] = info; - - return(0); - -} - -/* - * labelcl_info_connectpt_set - Sets the connectpt. - */ -int -labelcl_info_connectpt_set(hwgfs_handle_t de, - hwgfs_handle_t connect_de) -{ - arbitrary_info_t old_info; - int rv; - - rv = labelcl_info_replace_IDX(de, HWGRAPH_CONNECTPT, - (arbitrary_info_t) connect_de, &old_info); - - if (rv) { - return(rv); - } - - return(0); -} - - -/* - * labelcl_info_get_IDX - Returns the information pointed at by index. - * - */ -int -labelcl_info_get_IDX(vertex_hdl_t de, - int index, - arbitrary_info_t *info) -{ - arbitrary_info_t *info_list_IDX; - labelcl_info_t *labelcl_info = NULL; - - if (de == NULL) - return(-1); - - labelcl_info = hwgfs_get_info(de); - if (labelcl_info == NULL) - return(-1); - - if (labelcl_info->hwcl_magic != LABELCL_MAGIC) - return(-1); - - if ( (index < 0) || (index >= HWGRAPH_NUM_INDEX_INFO) ) - return(-1); - - /* - * Return information at the appropriate index in this vertex. - */ - info_list_IDX = labelcl_info->IDX_list; - if (info != NULL) - *info = info_list_IDX[index]; - - return(0); -} - -/* - * labelcl_info_connectpt_get - Retrieve the connect point for a device entry. - */ -hwgfs_handle_t -labelcl_info_connectpt_get(hwgfs_handle_t de) -{ - int rv; - arbitrary_info_t info; - - rv = labelcl_info_get_IDX(de, HWGRAPH_CONNECTPT, &info); - if (rv) - return(NULL); - - return((hwgfs_handle_t) info); -} diff --git a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c deleted file mode 100644 index 2119e99af..000000000 --- a/arch/ia64/sn/io/hwgfs/ramfs.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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. - * - * Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved. - * - * Mostly shameless copied from Linus Torvalds' ramfs and thus - * Copyright (C) 2000 Linus Torvalds. - * 2000 Transmeta Corp. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* some random number */ -#define HWGFS_MAGIC 0x12061983 - -static struct super_operations hwgfs_ops; -static struct address_space_operations hwgfs_aops; -static struct file_operations hwgfs_file_operations; -static struct inode_operations hwgfs_file_inode_operations; -static struct inode_operations hwgfs_dir_inode_operations; - -static struct backing_dev_info hwgfs_backing_dev_info = { - .ra_pages = 0, /* No readahead */ - .memory_backed = 1, /* Does not contribute to dirty memory */ -}; - -static struct inode *hwgfs_get_inode(struct super_block *sb, int mode, dev_t dev) -{ - struct inode * inode = new_inode(sb); - - if (inode) { - inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; - inode->i_blksize = PAGE_CACHE_SIZE; - inode->i_blocks = 0; - inode->i_mapping->a_ops = &hwgfs_aops; - inode->i_mapping->backing_dev_info = &hwgfs_backing_dev_info; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_op = &hwgfs_file_inode_operations; - inode->i_fop = &hwgfs_file_operations; - break; - case S_IFDIR: - inode->i_op = &hwgfs_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - inode->i_nlink++; - break; - case S_IFLNK: - inode->i_op = &page_symlink_inode_operations; - break; - } - } - return inode; -} - -static int hwgfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) -{ - struct inode * inode = hwgfs_get_inode(dir->i_sb, mode, dev); - int error = -ENOSPC; - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ - error = 0; - } - return error; -} - -static int hwgfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) -{ - return hwgfs_mknod(dir, dentry, mode | S_IFDIR, 0); -} - -static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *unused) -{ - return hwgfs_mknod(dir, dentry, mode | S_IFREG, 0); -} - -static int hwgfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) -{ - struct inode *inode; - int error = -ENOSPC; - - inode = hwgfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); - if (inode) { - int l = strlen(symname)+1; - error = page_symlink(inode, symname, l); - if (!error) { - d_instantiate(dentry, inode); - dget(dentry); - } else - iput(inode); - } - return error; -} - -static struct address_space_operations hwgfs_aops = { - .readpage = simple_readpage, - .prepare_write = simple_prepare_write, - .commit_write = simple_commit_write -}; - -static struct file_operations hwgfs_file_operations = { - .read = generic_file_read, - .write = generic_file_write, - .mmap = generic_file_mmap, - .fsync = simple_sync_file, - .sendfile = generic_file_sendfile, -}; - -static struct inode_operations hwgfs_file_inode_operations = { - .getattr = simple_getattr, -}; - -static struct inode_operations hwgfs_dir_inode_operations = { - .create = hwgfs_create, - .lookup = simple_lookup, - .link = simple_link, - .unlink = simple_unlink, - .symlink = hwgfs_symlink, - .mkdir = hwgfs_mkdir, - .rmdir = simple_rmdir, - .mknod = hwgfs_mknod, - .rename = simple_rename, -}; - -static struct super_operations hwgfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, -}; - -static int hwgfs_fill_super(struct super_block * sb, void * data, int silent) -{ - struct inode * inode; - struct dentry * root; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = HWGFS_MAGIC; - sb->s_op = &hwgfs_ops; - inode = hwgfs_get_inode(sb, S_IFDIR | 0755, 0); - if (!inode) - return -ENOMEM; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); - return -ENOMEM; - } - sb->s_root = root; - return 0; -} - -static struct super_block *hwgfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return get_sb_single(fs_type, flags, data, hwgfs_fill_super); -} - -static struct file_system_type hwgfs_fs_type = { - .owner = THIS_MODULE, - .name = "hwgfs", - .get_sb = hwgfs_get_sb, - .kill_sb = kill_litter_super, -}; - -struct vfsmount *hwgfs_vfsmount; - -int __init init_hwgfs_fs(void) -{ - int error; - - error = register_filesystem(&hwgfs_fs_type); - if (error) - return error; - - hwgfs_vfsmount = kern_mount(&hwgfs_fs_type); - if (IS_ERR(hwgfs_vfsmount)) - goto fail; - return 0; - -fail: - unregister_filesystem(&hwgfs_fs_type); - return PTR_ERR(hwgfs_vfsmount); -} - -static void __exit exit_hwgfs_fs(void) -{ - unregister_filesystem(&hwgfs_fs_type); -} - -MODULE_LICENSE("GPL"); - -module_init(init_hwgfs_fs) -module_exit(exit_hwgfs_fs) diff --git a/arch/ia64/sn/io/io.c b/arch/ia64/sn/io/io.c deleted file mode 100644 index cfc38abd5..000000000 --- a/arch/ia64/sn/io/io.c +++ /dev/null @@ -1,739 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern xtalk_provider_t hub_provider; - -static int force_fire_and_forget = 1; -static int ignore_conveyor_override; - - -/* - * Implementation of hub iobus operations. - * - * Hub provides a crosstalk "iobus" on IP27 systems. These routines - * provide a platform-specific implementation of xtalk used by all xtalk - * cards on IP27 systems. - * - * Called from corresponding xtalk_* routines. - */ - - -/* PIO MANAGEMENT */ -/* For mapping system virtual address space to xtalk space on a specified widget */ - -/* - * Setup pio structures needed for a particular hub. - */ -static void -hub_pio_init(vertex_hdl_t hubv) -{ - xwidgetnum_t widget; - hubinfo_t hubinfo; - nasid_t nasid; - int bigwin; - hub_piomap_t hub_piomap; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - /* Initialize small window piomaps for this hub */ - for (widget=0; widget <= HUB_WIDGET_ID_MAX; widget++) { - hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); - hub_piomap->hpio_xtalk_info.xp_target = widget; - hub_piomap->hpio_xtalk_info.xp_xtalk_addr = 0; - hub_piomap->hpio_xtalk_info.xp_mapsz = SWIN_SIZE; - hub_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_SWIN_BASE(nasid, widget); - hub_piomap->hpio_hub = hubv; - hub_piomap->hpio_flags = HUB_PIOMAP_IS_VALID; - } - - /* Initialize big window piomaps for this hub */ - for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { - hub_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin); - hub_piomap->hpio_xtalk_info.xp_mapsz = BWIN_SIZE; - hub_piomap->hpio_hub = hubv; - hub_piomap->hpio_holdcnt = 0; - hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW; - IIO_ITTE_DISABLE(nasid, bigwin); - } - hub_set_piomode(nasid, HUB_PIO_CONVEYOR); - - spin_lock_init(&hubinfo->h_bwlock); - init_waitqueue_head(&hubinfo->h_bwwait); -} - -/* - * Create a caddr_t-to-xtalk_addr mapping. - * - * Use a small window if possible (that's the usual case), but - * manage big windows if needed. Big window mappings can be - * either FIXED or UNFIXED -- we keep at least 1 big window available - * for UNFIXED mappings. - * - * Returns an opaque pointer-sized type which can be passed to - * other hub_pio_* routines on success, or NULL if the request - * cannot be satisfied. - */ -/* ARGSUSED */ -hub_piomap_t -hub_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) /* defined in sys/pio.h */ -{ - xwidget_info_t widget_info = xwidget_info_get(dev); - xwidgetnum_t widget = xwidget_info_id_get(widget_info); - vertex_hdl_t hubv = xwidget_info_master_get(widget_info); - hubinfo_t hubinfo; - hub_piomap_t bw_piomap; - int bigwin, free_bw_index; - nasid_t nasid; - volatile hubreg_t junk; - caddr_t kvaddr; -#ifdef PIOMAP_UNC_ACC_SPACE - uint64_t addr; -#endif - - /* sanity check */ - if (byte_count_max > byte_count) - return NULL; - - hubinfo_get(hubv, &hubinfo); - - /* If xtalk_addr range is mapped by a small window, we don't have - * to do much - */ - if (xtalk_addr + byte_count <= SWIN_SIZE) { - hub_piomap_t piomap; - - piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); -#ifdef PIOMAP_UNC_ACC_SPACE - if (flags & PIOMAP_UNC_ACC) { - addr = (uint64_t)piomap->hpio_xtalk_info.xp_kvaddr; - addr |= PIOMAP_UNC_ACC_SPACE; - piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)addr; - } -#endif - return piomap; - } - - /* We need to use a big window mapping. */ - - /* - * TBD: Allow requests that would consume multiple big windows -- - * split the request up and use multiple mapping entries. - * For now, reject requests that span big windows. - */ - if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE) - return NULL; - - - /* Round xtalk address down for big window alignement */ - xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1); - - /* - * Check to see if an existing big window mapping will suffice. - */ -tryagain: - free_bw_index = -1; - spin_lock(&hubinfo->h_bwlock); - for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { - bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin); - - /* If mapping is not valid, skip it */ - if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) { - free_bw_index = bigwin; - continue; - } - - /* - * If mapping is UNFIXED, skip it. We don't allow sharing - * of UNFIXED mappings, because this would allow starvation. - */ - if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED)) - continue; - - if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr && - widget == bw_piomap->hpio_xtalk_info.xp_target) { - bw_piomap->hpio_holdcnt++; - spin_unlock(&hubinfo->h_bwlock); - return bw_piomap; - } - } - - /* - * None of the existing big window mappings will work for us -- - * we need to establish a new mapping. - */ - - /* Insure that we don't consume all big windows with FIXED mappings */ - if (flags & PIOMAP_FIXED) { - if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) { - ASSERT(free_bw_index >= 0); - hubinfo->h_num_big_window_fixed++; - } else { - bw_piomap = NULL; - goto done; - } - } else /* PIOMAP_UNFIXED */ { - if (free_bw_index < 0) { - if (flags & PIOMAP_NOSLEEP) { - bw_piomap = NULL; - goto done; - } else { - DECLARE_WAITQUEUE(wait, current); - - spin_unlock(&hubinfo->h_bwlock); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue_exclusive(&hubinfo->h_bwwait, &wait); - schedule(); - remove_wait_queue(&hubinfo->h_bwwait, &wait); - goto tryagain; - } - } - } - - - /* OK! Allocate big window free_bw_index for this mapping. */ - /* - * The code below does a PIO write to setup an ITTE entry. - * We need to prevent other CPUs from seeing our updated memory - * shadow of the ITTE (in the piomap) until the ITTE entry is - * actually set up; otherwise, another CPU might attempt a PIO - * prematurely. - * - * Also, the only way we can know that an entry has been received - * by the hub and can be used by future PIO reads/writes is by - * reading back the ITTE entry after writing it. - * - * For these two reasons, we PIO read back the ITTE entry after - * we write it. - */ - - nasid = hubinfo->h_nasid; - IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); - junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index)); - - bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index); - bw_piomap->hpio_xtalk_info.xp_dev = dev; - bw_piomap->hpio_xtalk_info.xp_target = widget; - bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr; - kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index); -#ifdef PIOMAP_UNC_ACC_SPACE - if (flags & PIOMAP_UNC_ACC) { - addr = (uint64_t)kvaddr; - addr |= PIOMAP_UNC_ACC_SPACE; - kvaddr = (caddr_t)addr; - } -#endif - bw_piomap->hpio_xtalk_info.xp_kvaddr = kvaddr; - bw_piomap->hpio_holdcnt++; - bw_piomap->hpio_bigwin_num = free_bw_index; - - if (flags & PIOMAP_FIXED) - bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED; - else - bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID; - -done: - spin_unlock(&hubinfo->h_bwlock); - return bw_piomap; -} - -/* - * hub_piomap_free destroys a caddr_t-to-xtalk pio mapping and frees - * any associated mapping resources. - * - * If this * piomap was handled with a small window, or if it was handled - * in a big window that's still in use by someone else, then there's - * nothing to do. On the other hand, if this mapping was handled - * with a big window, AND if we were the final user of that mapping, - * then destroy the mapping. - */ -void -hub_piomap_free(hub_piomap_t hub_piomap) -{ - vertex_hdl_t hubv; - hubinfo_t hubinfo; - nasid_t nasid; - - /* - * Small windows are permanently mapped to corresponding widgets, - * so there're no resources to free. - */ - if (!(hub_piomap->hpio_flags & HUB_PIOMAP_IS_BIGWINDOW)) - return; - - ASSERT(hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID); - ASSERT(hub_piomap->hpio_holdcnt > 0); - - hubv = hub_piomap->hpio_hub; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - spin_lock(&hubinfo->h_bwlock); - - /* - * If this is the last hold on this mapping, free it. - */ - if (--hub_piomap->hpio_holdcnt == 0) { - IIO_ITTE_DISABLE(nasid, hub_piomap->hpio_bigwin_num ); - - if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED) { - hub_piomap->hpio_flags &= ~(HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED); - hubinfo->h_num_big_window_fixed--; - ASSERT(hubinfo->h_num_big_window_fixed >= 0); - } else - hub_piomap->hpio_flags &= ~HUB_PIOMAP_IS_VALID; - - wake_up(&hubinfo->h_bwwait); - } - - spin_unlock(&hubinfo->h_bwlock); -} - -/* - * Establish a mapping to a given xtalk address range using the resources - * allocated earlier. - */ -caddr_t -hub_piomap_addr(hub_piomap_t hub_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk address */ - size_t byte_count) /* map this many bytes */ -{ - /* Verify that range can be mapped using the specified piomap */ - if (xtalk_addr < hub_piomap->hpio_xtalk_info.xp_xtalk_addr) - return 0; - - if (xtalk_addr + byte_count > - ( hub_piomap->hpio_xtalk_info.xp_xtalk_addr + - hub_piomap->hpio_xtalk_info.xp_mapsz)) - return 0; - - if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID) - return hub_piomap->hpio_xtalk_info.xp_kvaddr + - (xtalk_addr % hub_piomap->hpio_xtalk_info.xp_mapsz); - else - return 0; -} - - -/* - * Driver indicates that it's done with PIO's from an earlier piomap_addr. - */ -/* ARGSUSED */ -void -hub_piomap_done(hub_piomap_t hub_piomap) /* done with these mapping resources */ -{ - /* Nothing to do */ -} - - -/* - * For translations that require no mapping resources, supply a kernel virtual - * address that maps to the specified xtalk address range. - */ -/* ARGSUSED */ -caddr_t -hub_piotrans_addr( vertex_hdl_t dev, /* translate to this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags) /* (currently unused) */ -{ - xwidget_info_t widget_info = xwidget_info_get(dev); - xwidgetnum_t widget = xwidget_info_id_get(widget_info); - vertex_hdl_t hubv = xwidget_info_master_get(widget_info); - hub_piomap_t hub_piomap; - hubinfo_t hubinfo; - caddr_t addr; - - hubinfo_get(hubv, &hubinfo); - - if (xtalk_addr + byte_count <= SWIN_SIZE) { - hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); - addr = hub_piomap_addr(hub_piomap, xtalk_addr, byte_count); -#ifdef PIOMAP_UNC_ACC_SPACE - if (flags & PIOMAP_UNC_ACC) { - uint64_t iaddr; - iaddr = (uint64_t)addr; - iaddr |= PIOMAP_UNC_ACC_SPACE; - addr = (caddr_t)iaddr; - } -#endif - return addr; - } else - return 0; -} - - -/* DMA MANAGEMENT */ -/* Mapping from crosstalk space to system physical space */ - - -/* - * Allocate resources needed to set up DMA mappings up to a specified size - * on a specified adapter. - * - * We don't actually use the adapter ID for anything. It's just the adapter - * that the lower level driver plans to use for DMA. - */ -/* ARGSUSED */ -hub_dmamap_t -hub_dmamap_alloc( vertex_hdl_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) /* defined in dma.h */ -{ - hub_dmamap_t dmamap; - xwidget_info_t widget_info = xwidget_info_get(dev); - xwidgetnum_t widget = xwidget_info_id_get(widget_info); - vertex_hdl_t hubv = xwidget_info_master_get(widget_info); - - dmamap = kmalloc(sizeof(struct hub_dmamap_s), GFP_ATOMIC); - dmamap->hdma_xtalk_info.xd_dev = dev; - dmamap->hdma_xtalk_info.xd_target = widget; - dmamap->hdma_hub = hubv; - dmamap->hdma_flags = HUB_DMAMAP_IS_VALID; - if (flags & XTALK_FIXED) - dmamap->hdma_flags |= HUB_DMAMAP_IS_FIXED; - - return dmamap; -} - -/* - * Destroy a DMA mapping from crosstalk space to system address space. - * There is no actual mapping hardware to destroy, but we at least mark - * the dmamap INVALID and free the space that it took. - */ -void -hub_dmamap_free(hub_dmamap_t hub_dmamap) -{ - hub_dmamap->hdma_flags &= ~HUB_DMAMAP_IS_VALID; - kfree(hub_dmamap); -} - -/* - * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc. - * Return an appropriate crosstalk address range that maps to the specified physical - * address range. - */ -/* ARGSUSED */ -extern iopaddr_t -hub_dmamap_addr( hub_dmamap_t dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) /* map this many bytes */ -{ - vertex_hdl_t vhdl; - - ASSERT(dmamap->hdma_flags & HUB_DMAMAP_IS_VALID); - - if (dmamap->hdma_flags & HUB_DMAMAP_USED) { - /* If the map is FIXED, re-use is OK. */ - if (!(dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { - char name[MAXDEVNAME]; - vhdl = dmamap->hdma_xtalk_info.xd_dev; - printk(KERN_WARNING "%s: hub_dmamap_addr re-uses dmamap.\n", vertex_to_name(vhdl, name, MAXDEVNAME)); - } - } else { - dmamap->hdma_flags |= HUB_DMAMAP_USED; - } - - /* There isn't actually any DMA mapping hardware on the hub. */ - return (PHYS_TO_DMA(paddr)); -} - -/* - * Driver indicates that it has completed whatever DMA it may have started - * after an earlier dmamap_addr call. - */ -void -hub_dmamap_done(hub_dmamap_t hub_dmamap) /* done with these mapping resources */ -{ - vertex_hdl_t vhdl; - - if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) { - hub_dmamap->hdma_flags &= ~HUB_DMAMAP_USED; - } else { - /* If the map is FIXED, re-done is OK. */ - if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) { - char name[MAXDEVNAME]; - vhdl = hub_dmamap->hdma_xtalk_info.xd_dev; - printk(KERN_WARNING "%s: hub_dmamap_done already done with dmamap\n", vertex_to_name(vhdl, name, MAXDEVNAME)); - } - } -} - -/* - * Translate a single system physical address into a crosstalk address. - */ -/* ARGSUSED */ -iopaddr_t -hub_dmatrans_addr( vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) /* defined in dma.h */ -{ - return (PHYS_TO_DMA(paddr)); -} - -/*ARGSUSED*/ -void -hub_dmamap_drain( hub_dmamap_t map) -{ - /* XXX- flush caches, if cache coherency WAR is needed */ -} - -/*ARGSUSED*/ -void -hub_dmaaddr_drain( vertex_hdl_t vhdl, - paddr_t addr, - size_t bytes) -{ - /* XXX- flush caches, if cache coherency WAR is needed */ -} - - -/* CONFIGURATION MANAGEMENT */ - -/* - * Perform initializations that allow this hub to start crosstalk support. - */ -void -hub_provider_startup(vertex_hdl_t hubv) -{ - hubinfo_t hubinfo; - - hubinfo_get(hubv, &hubinfo); - hub_pio_init(hubv); - intr_init_vecblk(nasid_to_cnodeid(hubinfo->h_nasid)); -} - -/* - * Shutdown crosstalk support from a hub. - */ -void -hub_provider_shutdown(vertex_hdl_t hub) -{ - /* TBD */ - xtalk_provider_unregister(hub); -} - -/* - * Check that an address is in the real small window widget 0 space - * or else in the big window we're using to emulate small window 0 - * in the kernel. - */ -int -hub_check_is_widget0(void *addr) -{ - nasid_t nasid = NASID_GET(addr); - - if (((unsigned long)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) && - ((unsigned long)addr < RAW_NODE_SWIN_BASE(nasid, 1))) - return 1; - return 0; -} - - -/* - * Check that two addresses use the same widget - */ -int -hub_check_window_equiv(void *addra, void *addrb) -{ - if (hub_check_is_widget0(addra) && hub_check_is_widget0(addrb)) - return 1; - - /* XXX - Assume this is really a small window address */ - if (WIDGETID_GET((unsigned long)addra) == - WIDGETID_GET((unsigned long)addrb)) - return 1; - - return 0; -} - - -/* - * hub_setup_prb(nasid, prbnum, credits, conveyor) - * - * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, - * put it into conveyor belt mode with the specified number of credits. - */ -void -hub_setup_prb(nasid_t nasid, int prbnum, int credits, int conveyor) -{ - iprb_t prb; - int prb_offset; - - if (force_fire_and_forget && !ignore_conveyor_override) - if (conveyor == HUB_PIO_CONVEYOR) - conveyor = HUB_PIO_FIRE_N_FORGET; - - /* - * Get the current register value. - */ - prb_offset = IIO_IOPRB(prbnum); - prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); - - /* - * Clear out some fields. - */ - prb.iprb_ovflow = 1; - prb.iprb_bnakctr = 0; - prb.iprb_anakctr = 0; - - /* - * Enable or disable fire-and-forget mode. - */ - prb.iprb_ff = ((conveyor == HUB_PIO_CONVEYOR) ? 0 : 1); - - /* - * Set the appropriate number of PIO cresits for the widget. - */ - prb.iprb_xtalkctr = credits; - - /* - * Store the new value to the register. - */ - REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); -} - -/* - * hub_set_piomode() - * - * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" - * mode. To do this, we have to make absolutely sure that no PIOs - * are in progress so we turn off access to all widgets for the duration - * of the function. - * - * XXX - This code should really check what kind of widget we're talking - * to. Bridges can only handle three requests, but XG will do more. - * How many can crossbow handle to widget 0? We're assuming 1. - * - * XXX - There is a bug in the crossbow that link reset PIOs do not - * return write responses. The easiest solution to this problem is to - * leave widget 0 (xbow) in fire-and-forget mode at all times. This - * only affects pio's to xbow registers, which should be rare. - */ -void -hub_set_piomode(nasid_t nasid, int conveyor) -{ - hubreg_t ii_iowa; - int direct_connect; - hubii_wcr_t ii_wcr; - int prbnum; - - ASSERT(nasid_to_cnodeid(nasid) != INVALID_CNODEID); - - ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); - direct_connect = ii_wcr.iwcr_dir_con; - - if (direct_connect) { - /* - * Assume a bridge here. - */ - hub_setup_prb(nasid, 0, 3, conveyor); - } else { - /* - * Assume a crossbow here. - */ - hub_setup_prb(nasid, 0, 1, conveyor); - } - - for (prbnum = HUB_WIDGET_ID_MIN; prbnum <= HUB_WIDGET_ID_MAX; prbnum++) { - /* - * XXX - Here's where we should take the widget type into - * when account assigning credits. - */ - /* Always set the PRBs in fire-and-forget mode */ - hub_setup_prb(nasid, prbnum, 3, conveyor); - } - - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); -} -/* Interface to allow special drivers to set hub specific - * device flags. - * Return 0 on failure , 1 on success - */ -int -hub_widget_flags_set(nasid_t nasid, - xwidgetnum_t widget_num, - hub_widget_flags_t flags) -{ - - ASSERT((flags & HUB_WIDGET_FLAGS) == flags); - - if (flags & HUB_PIO_CONVEYOR) { - hub_setup_prb(nasid,widget_num, - 3,HUB_PIO_CONVEYOR); /* set the PRB in conveyor - * belt mode with 3 credits - */ - } else if (flags & HUB_PIO_FIRE_N_FORGET) { - hub_setup_prb(nasid,widget_num, - 3,HUB_PIO_FIRE_N_FORGET); /* set the PRB in fire - * and forget mode - */ - } - - return 1; -} - -/* - * A pointer to this structure hangs off of every hub hwgraph vertex. - * The generic xtalk layer may indirect through it to get to this specific - * crosstalk bus provider. - */ -xtalk_provider_t hub_provider = { - .piomap_alloc = (xtalk_piomap_alloc_f *) hub_piomap_alloc, - .piomap_free = (xtalk_piomap_free_f *) hub_piomap_free, - .piomap_addr = (xtalk_piomap_addr_f *) hub_piomap_addr, - .piomap_done = (xtalk_piomap_done_f *) hub_piomap_done, - .piotrans_addr = (xtalk_piotrans_addr_f *) hub_piotrans_addr, - - .dmamap_alloc = (xtalk_dmamap_alloc_f *) hub_dmamap_alloc, - .dmamap_free = (xtalk_dmamap_free_f *) hub_dmamap_free, - .dmamap_addr = (xtalk_dmamap_addr_f *) hub_dmamap_addr, - .dmamap_done = (xtalk_dmamap_done_f *) hub_dmamap_done, - .dmatrans_addr = (xtalk_dmatrans_addr_f *) hub_dmatrans_addr, - .dmamap_drain = (xtalk_dmamap_drain_f *) hub_dmamap_drain, - .dmaaddr_drain = (xtalk_dmaaddr_drain_f *) hub_dmaaddr_drain, - - .intr_alloc = (xtalk_intr_alloc_f *) hub_intr_alloc, - .intr_alloc_nothd = (xtalk_intr_alloc_f *) hub_intr_alloc_nothd, - .intr_free = (xtalk_intr_free_f *) hub_intr_free, - .intr_connect = (xtalk_intr_connect_f *) hub_intr_connect, - .intr_disconnect = (xtalk_intr_disconnect_f *) hub_intr_disconnect, - .provider_startup = (xtalk_provider_startup_f *) hub_provider_startup, - .provider_shutdown = (xtalk_provider_shutdown_f *) hub_provider_shutdown, -}; diff --git a/arch/ia64/sn/io/machvec/Makefile b/arch/ia64/sn/io/machvec/Makefile deleted file mode 100644 index 64777696c..000000000 --- a/arch/ia64/sn/io/machvec/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 io routines. - -obj-y += pci.o pci_dma.o pci_bus_cvlink.o iomv.o diff --git a/arch/ia64/sn/io/machvec/iomv.c b/arch/ia64/sn/io/machvec/iomv.c deleted file mode 100644 index 10ee752ea..000000000 --- a/arch/ia64/sn/io/machvec/iomv.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * sn_io_addr - convert an in/out port to an i/o address - * @port: port to convert - * - * Legacy in/out instructions are converted to ld/st instructions - * on IA64. This routine will convert a port number into a valid - * SN i/o address. Used by sn_in*() and sn_out*(). - */ -void * -sn_io_addr(unsigned long port) -{ - if (!IS_RUNNING_ON_SIMULATOR()) { - /* On sn2, legacy I/O ports don't point at anything */ - if (port < 64*1024) - return 0; - return( (void *) (port | __IA64_UNCACHED_OFFSET)); - } else { - /* but the simulator uses them... */ - unsigned long io_base; - unsigned long addr; - - /* - * word align port, but need more than 10 bits - * for accessing registers in bedrock local block - * (so we don't do port&0xfff) - */ - if ((port >= 0x1f0 && port <= 0x1f7) || - port == 0x3f6 || port == 0x3f7) { - io_base = (0xc000000fcc000000 | ((unsigned long)get_nasid() << 38)); - addr = io_base | ((port >> 2) << 12) | (port & 0xfff); - } else { - addr = __ia64_get_io_port_base() | ((port >> 2) << 2); - } - return(void *) addr; - } -} - -EXPORT_SYMBOL(sn_io_addr); - -/** - * sn_mmiob - I/O space memory barrier - * - * Acts as a memory mapped I/O barrier for platforms that queue writes to - * I/O space. This ensures that subsequent writes to I/O space arrive after - * all previous writes. For most ia64 platforms, this is a simple - * 'mf.a' instruction. For other platforms, mmiob() may have to read - * a chipset register to ensure ordering. - * - * On SN2, we wait for the PIO_WRITE_STATUS SHub register to clear. - * See PV 871084 for details about the WAR about zero value. - * - */ -void -sn_mmiob (void) -{ - while ((((volatile unsigned long) (*pda->pio_write_status_addr)) & SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) != - SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT_MASK) - cpu_relax(); -} -EXPORT_SYMBOL(sn_mmiob); diff --git a/arch/ia64/sn/io/machvec/pci.c b/arch/ia64/sn/io/machvec/pci.c deleted file mode 100644 index 56f81cc26..000000000 --- a/arch/ia64/sn/io/machvec/pci.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SNI64 specific PCI support for SNI IO. - * - * 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. - * - * Copyright (c) 1997, 1998, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ -#include -#include - -/* - * These routines are only used during sn_pci_init for probing each bus, and - * can probably be removed with a little more cleanup now that the SAL routines - * work on sn2. - */ - -extern vertex_hdl_t devfn_to_vertex(unsigned char bus, unsigned char devfn); - -int sn_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) -{ - unsigned long res = 0; - vertex_hdl_t device_vertex; - - device_vertex = devfn_to_vertex(bus->number, devfn); - - if (!device_vertex) - return PCIBIOS_DEVICE_NOT_FOUND; - - res = pciio_config_get(device_vertex, (unsigned)where, size); - *val = (u32)res; - return PCIBIOS_SUCCESSFUL; -} - -int sn_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) -{ - vertex_hdl_t device_vertex; - - device_vertex = devfn_to_vertex(bus->number, devfn); - - if (!device_vertex) - return PCIBIOS_DEVICE_NOT_FOUND; - - pciio_config_set(device_vertex, (unsigned)where, size, (uint64_t)val); - return PCIBIOS_SUCCESSFUL; -} - -struct pci_ops sn_pci_ops = { - .read = sn_read_config, - .write = sn_write_config, -}; diff --git a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c b/arch/ia64/sn/io/machvec/pci_bus_cvlink.c deleted file mode 100644 index ba9e42c12..000000000 --- a/arch/ia64/sn/io/machvec/pci_bus_cvlink.c +++ /dev/null @@ -1,906 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -extern int bridge_rev_b_data_check_disable; - -vertex_hdl_t busnum_to_pcibr_vhdl[MAX_PCI_XWIDGET]; -nasid_t busnum_to_nid[MAX_PCI_XWIDGET]; -void * busnum_to_atedmamaps[MAX_PCI_XWIDGET]; -unsigned char num_bridges; -static int done_probing; -extern irqpda_t *irqpdaindr; - -static int pci_bus_map_create(struct pcibr_list_s *softlistp, moduleid_t io_moduleid); -vertex_hdl_t devfn_to_vertex(unsigned char busnum, unsigned int devfn); - -extern void register_pcibr_intr(int irq, pcibr_intr_t intr); - -static struct sn_flush_device_list *sn_dma_flush_init(unsigned long start, - unsigned long end, - int idx, int pin, int slot); -extern int cbrick_type_get_nasid(nasid_t); -extern void ioconfig_bus_new_entries(void); -extern void ioconfig_get_busnum(char *, int *); -extern int iomoduleid_get(nasid_t); -extern int pcibr_widget_to_bus(vertex_hdl_t); -extern int isIO9(int); - -#define IS_OPUS(nasid) (cbrick_type_get_nasid(nasid) == MODULE_OPUSBRICK) -#define IS_ALTIX(nasid) (cbrick_type_get_nasid(nasid) == MODULE_CBRICK) - -/* - * Init the provider asic for a given device - */ - -static inline void __init -set_pci_provider(struct sn_device_sysdata *device_sysdata) -{ - pciio_info_t pciio_info = pciio_info_get(device_sysdata->vhdl); - - device_sysdata->pci_provider = pciio_info_pops_get(pciio_info); -} - -/* - * pci_bus_cvlink_init() - To be called once during initialization before - * SGI IO Infrastructure init is called. - */ -int -pci_bus_cvlink_init(void) -{ - - extern int ioconfig_bus_init(void); - - memset(busnum_to_pcibr_vhdl, 0x0, sizeof(vertex_hdl_t) * MAX_PCI_XWIDGET); - memset(busnum_to_nid, 0x0, sizeof(nasid_t) * MAX_PCI_XWIDGET); - - memset(busnum_to_atedmamaps, 0x0, sizeof(void *) * MAX_PCI_XWIDGET); - - num_bridges = 0; - - return ioconfig_bus_init(); -} - -/* - * pci_bus_to_vertex() - Given a logical Linux Bus Number returns the associated - * pci bus vertex from the SGI IO Infrastructure. - */ -static inline vertex_hdl_t -pci_bus_to_vertex(unsigned char busnum) -{ - - vertex_hdl_t pci_bus = NULL; - - - /* - * First get the xwidget vertex. - */ - pci_bus = busnum_to_pcibr_vhdl[busnum]; - return(pci_bus); -} - -/* - * devfn_to_vertex() - returns the vertex of the device given the bus, slot, - * and function numbers. - */ -vertex_hdl_t -devfn_to_vertex(unsigned char busnum, unsigned int devfn) -{ - - int slot = 0; - int func = 0; - char name[16]; - vertex_hdl_t pci_bus = NULL; - vertex_hdl_t device_vertex = (vertex_hdl_t)NULL; - - /* - * Go get the pci bus vertex. - */ - pci_bus = pci_bus_to_vertex(busnum); - if (!pci_bus) { - /* - * During probing, the Linux pci code invents non-existent - * bus numbers and pci_dev structures and tries to access - * them to determine existence. Don't crib during probing. - */ - if (done_probing) - printk("devfn_to_vertex: Invalid bus number %d given.\n", busnum); - return(NULL); - } - - - /* - * Go get the slot&function vertex. - * Should call pciio_slot_func_to_name() when ready. - */ - slot = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); - - /* - * For a NON Multi-function card the name of the device looks like: - * ../pci/1, ../pci/2 .. - */ - if (func == 0) { - sprintf(name, "%d", slot); - if (hwgraph_traverse(pci_bus, name, &device_vertex) == - GRAPH_SUCCESS) { - if (device_vertex) { - return(device_vertex); - } - } - } - - /* - * This maybe a multifunction card. It's names look like: - * ../pci/1a, ../pci/1b, etc. - */ - sprintf(name, "%d%c", slot, 'a'+func); - if (hwgraph_traverse(pci_bus, name, &device_vertex) != GRAPH_SUCCESS) { - if (!device_vertex) { - return(NULL); - } - } - - return(device_vertex); -} - -/* - * sn_alloc_pci_sysdata() - This routine allocates a pci controller - * which is expected as the pci_dev and pci_bus sysdata by the Linux - * PCI infrastructure. - */ -static struct pci_controller * -sn_alloc_pci_sysdata(void) -{ - struct pci_controller *pci_sysdata; - - pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL); - if (!pci_sysdata) - return NULL; - - memset(pci_sysdata, 0, sizeof(*pci_sysdata)); - return pci_sysdata; -} - -/* - * sn_pci_fixup_bus() - This routine sets up a bus's resources - * consistent with the Linux PCI abstraction layer. - */ -static int __init -sn_pci_fixup_bus(struct pci_bus *bus) -{ - struct pci_controller *pci_sysdata; - struct sn_widget_sysdata *widget_sysdata; - - pci_sysdata = sn_alloc_pci_sysdata(); - if (!pci_sysdata) { - printk(KERN_WARNING "sn_pci_fixup_bus(): Unable to " - "allocate memory for pci_sysdata\n"); - return -ENOMEM; - } - widget_sysdata = kmalloc(sizeof(struct sn_widget_sysdata), - GFP_KERNEL); - if (!widget_sysdata) { - printk(KERN_WARNING "sn_pci_fixup_bus(): Unable to " - "allocate memory for widget_sysdata\n"); - kfree(pci_sysdata); - return -ENOMEM; - } - - widget_sysdata->vhdl = pci_bus_to_vertex(bus->number); - pci_sysdata->platform_data = (void *)widget_sysdata; - bus->sysdata = pci_sysdata; - return 0; -} - - -/* - * sn_pci_fixup_slot() - This routine sets up a slot's resources - * consistent with the Linux PCI abstraction layer. Resources acquired - * from our PCI provider include PIO maps to BAR space and interrupt - * objects. - */ -static int -sn_pci_fixup_slot(struct pci_dev *dev) -{ - extern int bit_pos_to_irq(int); - unsigned int irq; - int idx; - u16 cmd; - vertex_hdl_t vhdl; - unsigned long size; - struct pci_controller *pci_sysdata; - struct sn_device_sysdata *device_sysdata; - pciio_intr_line_t lines = 0; - vertex_hdl_t device_vertex; - pciio_provider_t *pci_provider; - pciio_intr_t intr_handle; - - /* Allocate a controller structure */ - pci_sysdata = sn_alloc_pci_sysdata(); - if (!pci_sysdata) { - printk(KERN_WARNING "sn_pci_fixup_slot: Unable to " - "allocate memory for pci_sysdata\n"); - return -ENOMEM; - } - - /* Set the device vertex */ - device_sysdata = kmalloc(sizeof(struct sn_device_sysdata), GFP_KERNEL); - if (!device_sysdata) { - printk(KERN_WARNING "sn_pci_fixup_slot: Unable to " - "allocate memory for device_sysdata\n"); - kfree(pci_sysdata); - return -ENOMEM; - } - - device_sysdata->vhdl = devfn_to_vertex(dev->bus->number, dev->devfn); - pci_sysdata->platform_data = (void *) device_sysdata; - dev->sysdata = pci_sysdata; - set_pci_provider(device_sysdata); - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - - /* - * Set the resources address correctly. The assumption here - * is that the addresses in the resource structure has been - * read from the card and it was set in the card by our - * Infrastructure. NOTE: PIC and TIOCP don't have big-window - * upport for PCI I/O space. So by mapping the I/O space - * first we will attempt to use Device(x) registers for I/O - * BARs (which can't use big windows like MEM BARs can). - */ - vhdl = device_sysdata->vhdl; - - /* Allocate the IORESOURCE_IO space first */ - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - unsigned long start, end, addr; - - device_sysdata->pio_map[idx] = NULL; - - if (!(dev->resource[idx].flags & IORESOURCE_IO)) - continue; - - start = dev->resource[idx].start; - end = dev->resource[idx].end; - size = end - start; - if (!size) - continue; - - addr = (unsigned long)pciio_pio_addr(vhdl, 0, - PCIIO_SPACE_WIN(idx), 0, size, - &device_sysdata->pio_map[idx], 0); - - if (!addr) { - dev->resource[idx].start = 0; - dev->resource[idx].end = 0; - printk("sn_pci_fixup(): pio map failure for " - "%s bar%d\n", dev->slot_name, idx); - } else { - addr |= __IA64_UNCACHED_OFFSET; - dev->resource[idx].start = addr; - dev->resource[idx].end = addr + size; - } - - if (dev->resource[idx].flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - } - - /* Allocate the IORESOURCE_MEM space next */ - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - unsigned long start, end, addr; - - if ((dev->resource[idx].flags & IORESOURCE_IO)) - continue; - - start = dev->resource[idx].start; - end = dev->resource[idx].end; - size = end - start; - if (!size) - continue; - - addr = (unsigned long)pciio_pio_addr(vhdl, 0, - PCIIO_SPACE_WIN(idx), 0, size, - &device_sysdata->pio_map[idx], 0); - - if (!addr) { - dev->resource[idx].start = 0; - dev->resource[idx].end = 0; - printk("sn_pci_fixup(): pio map failure for " - "%s bar%d\n", dev->slot_name, idx); - } else { - addr |= __IA64_UNCACHED_OFFSET; - dev->resource[idx].start = addr; - dev->resource[idx].end = addr + size; - } - - if (dev->resource[idx].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - - /* - * Assign addresses to the ROMs, but don't enable them yet - * Also note that we only map display card ROMs due to PIO mapping - * space scarcity. - */ - if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { - unsigned long addr; - size = dev->resource[PCI_ROM_RESOURCE].end - - dev->resource[PCI_ROM_RESOURCE].start; - - if (size) { - addr = (unsigned long) pciio_pio_addr(vhdl, 0, - PCIIO_SPACE_ROM, - 0, size, 0, PIOMAP_FIXED); - if (!addr) { - dev->resource[PCI_ROM_RESOURCE].start = 0; - dev->resource[PCI_ROM_RESOURCE].end = 0; - printk("sn_pci_fixup(): ROM pio map failure " - "for %s\n", dev->slot_name); - } - addr |= __IA64_UNCACHED_OFFSET; - dev->resource[PCI_ROM_RESOURCE].start = addr; - dev->resource[PCI_ROM_RESOURCE].end = addr + size; - if (dev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - } - - /* - * Update the Command Word on the Card. - */ - cmd |= PCI_COMMAND_MASTER; /* If the device doesn't support */ - /* bit gets dropped .. no harm */ - pci_write_config_word(dev, PCI_COMMAND, cmd); - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, (unsigned char *)&lines); - device_vertex = device_sysdata->vhdl; - pci_provider = device_sysdata->pci_provider; - device_sysdata->intr_handle = NULL; - - if (!lines) - return 0; - - irqpdaindr->curr = dev; - - intr_handle = (pci_provider->intr_alloc)(device_vertex, NULL, lines, device_vertex); - if (intr_handle == NULL) { - printk(KERN_WARNING "sn_pci_fixup: pcibr_intr_alloc() failed\n"); - kfree(pci_sysdata); - kfree(device_sysdata); - return -ENOMEM; - } - - device_sysdata->intr_handle = intr_handle; - irq = intr_handle->pi_irq; - irqpdaindr->device_dev[irq] = dev; - (pci_provider->intr_connect)(intr_handle, (intr_func_t)0, (intr_arg_t)0); - dev->irq = irq; - - register_pcibr_intr(irq, (pcibr_intr_t)intr_handle); - - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - int ibits = ((pcibr_intr_t)intr_handle)->bi_ibits; - int i; - - size = dev->resource[idx].end - - dev->resource[idx].start; - if (size == 0) continue; - - for (i=0; i<8; i++) { - if (ibits & (1 << i) ) { - extern pcibr_info_t pcibr_info_get(vertex_hdl_t); - device_sysdata->dma_flush_list = - sn_dma_flush_init(dev->resource[idx].start, - dev->resource[idx].end, - idx, - i, - PCIBR_INFO_SLOT_GET_EXT(pcibr_info_get(device_sysdata->vhdl))); - } - } - } - return 0; -} - -#ifdef CONFIG_HOTPLUG_PCI_SGI - -void -sn_dma_flush_clear(struct sn_flush_device_list *dma_flush_list, - unsigned long start, unsigned long end) -{ - - int i; - - dma_flush_list->pin = -1; - dma_flush_list->bus = -1; - dma_flush_list->slot = -1; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if ((dma_flush_list->bar_list[i].start == start) && - (dma_flush_list->bar_list[i].end == end)) { - dma_flush_list->bar_list[i].start = 0; - dma_flush_list->bar_list[i].end = 0; - break; - } - -} - -/* - * sn_pci_unfixup_slot() - This routine frees a slot's resources - * consistent with the Linux PCI abstraction layer. Resources released - * back to our PCI provider include PIO maps to BAR space and interrupt - * objects. - */ -void -sn_pci_unfixup_slot(struct pci_dev *dev) -{ - struct sn_device_sysdata *device_sysdata; - vertex_hdl_t vhdl; - pciio_intr_t intr_handle; - unsigned int irq; - unsigned long size; - int idx; - - device_sysdata = SN_DEVICE_SYSDATA(dev); - - vhdl = device_sysdata->vhdl; - - if (device_sysdata->dma_flush_list) - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - size = dev->resource[idx].end - - dev->resource[idx].start; - if (size == 0) continue; - - sn_dma_flush_clear(device_sysdata->dma_flush_list, - dev->resource[idx].start, - dev->resource[idx].end); - } - - intr_handle = device_sysdata->intr_handle; - if (intr_handle) { - extern void unregister_pcibr_intr(int, pcibr_intr_t); - irq = intr_handle->pi_irq; - irqpdaindr->device_dev[irq] = NULL; - unregister_pcibr_intr(irq, (pcibr_intr_t) intr_handle); - pciio_intr_disconnect(intr_handle); - pciio_intr_free(intr_handle); - } - - for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { - if (device_sysdata->pio_map[idx]) { - pciio_piomap_done (device_sysdata->pio_map[idx]); - pciio_piomap_free (device_sysdata->pio_map[idx]); - } - } - -} -#endif /* CONFIG_HOTPLUG_PCI_SGI */ - -struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; - -/* Initialize the data structures for flushing write buffers after a PIO read. - * The theory is: - * Take an unused int. pin and associate it with a pin that is in use. - * After a PIO read, force an interrupt on the unused pin, forcing a write buffer flush - * on the in use pin. This will prevent the race condition between PIO read responses and - * DMA writes. - */ -static struct sn_flush_device_list * -sn_dma_flush_init(unsigned long start, unsigned long end, int idx, int pin, int slot) -{ - nasid_t nasid; - unsigned long dnasid; - int wid_num; - int bus; - struct sn_flush_device_list *p; - void *b; - int bwin; - int i; - - nasid = NASID_GET(start); - wid_num = SWIN_WIDGETNUM(start); - bus = (start >> 23) & 0x1; - bwin = BWIN_WINDOWNUM(start); - - if (flush_nasid_list[nasid].widget_p == NULL) { - flush_nasid_list[nasid].widget_p = (struct sn_flush_device_list **)kmalloc((HUB_WIDGET_ID_MAX+1) * - sizeof(struct sn_flush_device_list *), GFP_KERNEL); - if (!flush_nasid_list[nasid].widget_p) { - printk(KERN_WARNING "sn_dma_flush_init: Cannot allocate memory for nasid list\n"); - return NULL; - } - memset(flush_nasid_list[nasid].widget_p, 0, (HUB_WIDGET_ID_MAX+1) * sizeof(struct sn_flush_device_list *)); - } - if (bwin > 0) { - int itte_index = bwin - 1; - unsigned long itte; - - itte = HUB_L(IIO_ITTE_GET(nasid, itte_index)); - flush_nasid_list[nasid].iio_itte[bwin] = itte; - wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) - & IIO_ITTE_WIDGET_MASK; - bus = itte & IIO_ITTE_OFFSET_MASK; - if (bus == 0x4 || bus == 0x8) { - bus = 0; - } else { - bus = 1; - } - } - - /* if it's IO9, bus 1, we don't care about slots 1 and 4. This is - * because these are the IOC4 slots and we don't flush them. - */ - if (isIO9(nasid) && bus == 0 && (slot == 1 || slot == 4)) { - return NULL; - } - if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) { - flush_nasid_list[nasid].widget_p[wid_num] = (struct sn_flush_device_list *)kmalloc( - DEV_PER_WIDGET * sizeof (struct sn_flush_device_list), GFP_KERNEL); - if (!flush_nasid_list[nasid].widget_p[wid_num]) { - printk(KERN_WARNING "sn_dma_flush_init: Cannot allocate memory for nasid sub-list\n"); - return NULL; - } - memset(flush_nasid_list[nasid].widget_p[wid_num], 0, - DEV_PER_WIDGET * sizeof (struct sn_flush_device_list)); - p = &flush_nasid_list[nasid].widget_p[wid_num][0]; - for (i=0; ibus = -1; - p->pin = -1; - p->slot = -1; - p++; - } - } - - p = &flush_nasid_list[nasid].widget_p[wid_num][0]; - for (i=0;ipin == pin && p->bus == bus && p->slot == slot) break; - if (p->pin < 0) { - p->pin = pin; - p->bus = bus; - p->slot = slot; - break; - } - p++; - } - - for (i=0; ibar_list[i].start == 0) { - p->bar_list[i].start = start; - p->bar_list[i].end = end; - break; - } - } - b = (void *)(NODE_SWIN_BASE(nasid, wid_num) | (bus << 23) ); - - /* If it's IO9, then slot 2 maps to slot 7 and slot 6 maps to slot 8. - * To see this is non-trivial. By drawing pictures and reading manuals and talking - * to HW guys, we can see that on IO9 bus 1, slots 7 and 8 are always unused. - * Further, since we short-circuit slots 1, 3, and 4 above, we only have to worry - * about the case when there is a card in slot 2. A multifunction card will appear - * to be in slot 6 (from an interrupt point of view) also. That's the most we'll - * have to worry about. A four function card will overload the interrupt lines in - * slot 2 and 6. - * We also need to special case the 12160 device in slot 3. Fortunately, we have - * a spare intr. line for pin 4, so we'll use that for the 12160. - * All other buses have slot 3 and 4 and slots 7 and 8 unused. Since we can only - * see slots 1 and 2 and slots 5 and 6 coming through here for those buses (this - * is true only on Pxbricks with 2 physical slots per bus), we just need to add - * 2 to the slot number to find an unused slot. - * We have convinced ourselves that we will never see a case where two different cards - * in two different slots will ever share an interrupt line, so there is no need to - * special case this. - */ - - if (isIO9(nasid) && ( (IS_ALTIX(nasid) && wid_num == 0xc) - || (IS_OPUS(nasid) && wid_num == 0xf) ) - && bus == 0) { - if (pin == 1) { - p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 6); - pcireg_bridge_intr_device_bit_set(b, (1<<18)); - dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - pcireg_bridge_intr_addr_set(b, 6, ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48))); - } else if (pin == 2) { /* 12160 SCSI device in IO9 */ - p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 4); - pcireg_bridge_intr_device_bit_set(b, (2<<12)); - dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - pcireg_bridge_intr_addr_set(b, 4, - ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48))); - } else { /* slot == 6 */ - p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, 7); - pcireg_bridge_intr_device_bit_set(b, (5<<21)); - dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - pcireg_bridge_intr_addr_set(b, 7, - ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48))); - } - } else { - p->force_int_addr = (unsigned long)pcireg_bridge_force_always_addr_get(b, (pin +2)); - pcireg_bridge_intr_device_bit_set(b, (pin << (pin * 3))); - dnasid = NASID_GET(virt_to_phys(&p->flush_addr)); - pcireg_bridge_intr_addr_set(b, (pin + 2), - ((virt_to_phys(&p->flush_addr) & 0xfffffffff) | - (dnasid << 36) | (0xfUL << 48))); - } - return p; -} - - -/* - * linux_bus_cvlink() Creates a link between the Linux PCI Bus number - * to the actual hardware component that it represents: - * /dev/hw/linux/busnum/0 -> ../../../hw/module/001c01/slab/0/Ibrick/xtalk/15/pci - * - * The bus vertex, when called to devfs_generate_path() returns: - * hw/module/001c01/slab/0/Ibrick/xtalk/15/pci - * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/0 - * hw/module/001c01/slab/1/Pbrick/xtalk/12/pci-x/1 - */ -void -linux_bus_cvlink(void) -{ - char name[8]; - int index; - - for (index=0; index < MAX_PCI_XWIDGET; index++) { - if (!busnum_to_pcibr_vhdl[index]) - continue; - - sprintf(name, "%x", index); - (void) hwgraph_edge_add(linux_busnum, busnum_to_pcibr_vhdl[index], - name); - } -} - -/* - * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. - * - * Linux PCI Bus numbers are assigned from lowest module_id numbers - * (rack/slot etc.) - */ -static int -pci_bus_map_create(struct pcibr_list_s *softlistp, moduleid_t moduleid) -{ - - int basebus_num, bus_number; - vertex_hdl_t pci_bus = softlistp->bl_vhdl; - char moduleid_str[16]; - - memset(moduleid_str, 0, 16); - format_module_id(moduleid_str, moduleid, MODULE_FORMAT_BRIEF); - (void) ioconfig_get_busnum((char *)moduleid_str, &basebus_num); - - /* - * Assign the correct bus number and also the nasid of this - * pci Xwidget. - */ - bus_number = basebus_num + pcibr_widget_to_bus(pci_bus); -#ifdef DEBUG - { - char hwpath[MAXDEVNAME] = "\0"; - extern int hwgraph_vertex_name_get(vertex_hdl_t, char *, uint); - - pcibr_soft_t pcibr_soft = softlistp->bl_soft; - hwgraph_vertex_name_get(pci_bus, hwpath, MAXDEVNAME); - printk("%s:\n\tbus_num %d, basebus_num %d, brick_bus %d, " - "bus_vhdl 0x%lx, brick_type %d\n", hwpath, bus_number, - basebus_num, pcibr_widget_to_bus(pci_bus), - (uint64_t)pci_bus, pcibr_soft->bs_bricktype); - } -#endif - busnum_to_pcibr_vhdl[bus_number] = pci_bus; - - /* - * Pre assign DMA maps needed for 32 Bits Page Map DMA. - */ - busnum_to_atedmamaps[bus_number] = (void *) vmalloc( - sizeof(struct pcibr_dmamap_s)*MAX_ATE_MAPS); - if (busnum_to_atedmamaps[bus_number] <= 0) { - printk("pci_bus_map_create: Cannot allocate memory for ate maps\n"); - return -1; - } - memset(busnum_to_atedmamaps[bus_number], 0x0, - sizeof(struct pcibr_dmamap_s) * MAX_ATE_MAPS); - return(0); -} - -/* - * pci_bus_to_hcl_cvlink() - This routine is called after SGI IO Infrastructure - * initialization has completed to set up the mappings between PCI BRIDGE - * ASIC and logical pci bus numbers. - * - * Must be called before pci_init() is invoked. - */ -int -pci_bus_to_hcl_cvlink(void) -{ - int i; - extern pcibr_list_p pcibr_list; - - for (i = 0; i < nummodules; i++) { - struct pcibr_list_s *softlistp = pcibr_list; - struct pcibr_list_s *first_in_list = NULL; - struct pcibr_list_s *last_in_list = NULL; - - /* Walk the list of pcibr_soft structs looking for matches */ - while (softlistp) { - struct pcibr_soft_s *pcibr_soft = softlistp->bl_soft; - moduleid_t moduleid; - - /* Is this PCI bus associated with this moduleid? */ - moduleid = NODE_MODULEID( - nasid_to_cnodeid(pcibr_soft->bs_nasid)); - if (sn_modules[i]->id == moduleid) { - struct pcibr_list_s *new_element; - - new_element = kmalloc(sizeof (struct pcibr_soft_s), GFP_KERNEL); - if (new_element == NULL) { - printk("%s: Couldn't allocate memory\n",__FUNCTION__); - return -ENOMEM; - } - new_element->bl_soft = softlistp->bl_soft; - new_element->bl_vhdl = softlistp->bl_vhdl; - new_element->bl_next = NULL; - - /* list empty so just put it on the list */ - if (first_in_list == NULL) { - first_in_list = new_element; - last_in_list = new_element; - softlistp = softlistp->bl_next; - continue; - } - - /* - * BASEIO IObricks attached to a module have - * a higher priority than non BASEIO IOBricks - * when it comes to persistant pci bus - * numbering, so put them on the front of the - * list. - */ - if (isIO9(pcibr_soft->bs_nasid)) { - new_element->bl_next = first_in_list; - first_in_list = new_element; - } else { - last_in_list->bl_next = new_element; - last_in_list = new_element; - } - } - softlistp = softlistp->bl_next; - } - - /* - * We now have a list of all the pci bridges associated with - * the module_id, sn_modules[i]. Call pci_bus_map_create() for - * each pci bridge - */ - softlistp = first_in_list; - while (softlistp) { - moduleid_t iobrick; - struct pcibr_list_s *next = softlistp->bl_next; - iobrick = iomoduleid_get(softlistp->bl_soft->bs_nasid); - pci_bus_map_create(softlistp, iobrick); - kfree(softlistp); - softlistp = next; - } - } - - /* - * Create the Linux PCI bus number vertex link. - */ - (void)linux_bus_cvlink(); - (void)ioconfig_bus_new_entries(); - - return(0); -} - -/* - * Ugly hack to get PCI setup until we have a proper ACPI namespace. - */ - -#define PCI_BUSES_TO_SCAN 256 - -extern struct pci_ops sn_pci_ops; -int __init -sn_pci_init (void) -{ - int i = 0; - struct pci_controller *controller; - struct list_head *ln; - struct pci_bus *pci_bus = NULL; - struct pci_dev *pci_dev = NULL; - int ret; -#ifdef CONFIG_PROC_FS - extern void register_sn_procfs(void); -#endif - extern void sgi_master_io_infr_init(void); - extern void sn_init_cpei_timer(void); - - - if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR()) - return 0; - - /* - * This is needed to avoid bounce limit checks in the blk layer - */ - ia64_max_iommu_merge_mask = ~PAGE_MASK; - - /* - * set pci_raw_ops, etc. - */ - sgi_master_io_infr_init(); - - sn_init_cpei_timer(); - -#ifdef CONFIG_PROC_FS - register_sn_procfs(); -#endif - - controller = kmalloc(sizeof(struct pci_controller), GFP_KERNEL); - if (!controller) { - printk(KERN_WARNING "cannot allocate PCI controller\n"); - return 0; - } - - memset(controller, 0, sizeof(struct pci_controller)); - - for (i = 0; i < PCI_BUSES_TO_SCAN; i++) - if (pci_bus_to_vertex(i)) - pci_scan_bus(i, &sn_pci_ops, controller); - - done_probing = 1; - - /* - * Initialize the pci bus vertex in the pci_bus struct. - */ - for( ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) { - pci_bus = pci_bus_b(ln); - ret = sn_pci_fixup_bus(pci_bus); - if ( ret ) { - printk(KERN_WARNING - "sn_pci_fixup: sn_pci_fixup_bus fails : error %d\n", - ret); - return 0; - } - } - - /* - * set the root start and end so that drivers calling check_region() - * won't see a conflict - */ - ioport_resource.start = 0xc000000000000000; - ioport_resource.end = 0xcfffffffffffffff; - - /* - * Set the root start and end for Mem Resource. - */ - iomem_resource.start = 0; - iomem_resource.end = 0xffffffffffffffff; - - /* - * Initialize the device vertex in the pci_dev struct. - */ - while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { - ret = sn_pci_fixup_slot(pci_dev); - if ( ret ) { - printk(KERN_WARNING - "sn_pci_fixup: sn_pci_fixup_slot fails : error %d\n", - ret); - return 0; - } - } - - return 0; -} - -subsys_initcall(sn_pci_init); diff --git a/arch/ia64/sn/io/machvec/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c deleted file mode 100644 index 4a3e76c54..000000000 --- a/arch/ia64/sn/io/machvec/pci_dma.c +++ /dev/null @@ -1,677 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. - * - * Routines for PCI DMA mapping. See Documentation/DMA-mapping.txt for - * a description of how these routines should be used. - */ - -#include -#include - -/* - * For ATE allocations - */ -pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); -void free_pciio_dmamap(pcibr_dmamap_t); -static struct pcibr_dmamap_s *find_sn_dma_map(dma_addr_t, unsigned char); -void sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); - -/* - * Toplogy stuff - */ -extern vertex_hdl_t busnum_to_pcibr_vhdl[]; -extern nasid_t busnum_to_nid[]; -extern void * busnum_to_atedmamaps[]; - -/** - * get_free_pciio_dmamap - find and allocate an ATE - * @pci_bus: PCI bus to get an entry for - * - * Finds and allocates an ATE on the PCI bus specified - * by @pci_bus. - */ -pciio_dmamap_t -get_free_pciio_dmamap(vertex_hdl_t pci_bus) -{ - int i; - struct pcibr_dmamap_s *sn_dma_map = NULL; - - /* - * Darn, we need to get the maps allocated for this bus. - */ - for (i = 0; i < MAX_PCI_XWIDGET; i++) { - if (busnum_to_pcibr_vhdl[i] == pci_bus) { - sn_dma_map = busnum_to_atedmamaps[i]; - } - } - - /* - * Now get a free dmamap entry from this list. - */ - for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { - if (!sn_dma_map->bd_dma_addr) { - sn_dma_map->bd_dma_addr = -1; - return( (pciio_dmamap_t) sn_dma_map ); - } - } - - return NULL; -} - -/** - * free_pciio_dmamap - free an ATE - * @dma_map: ATE to free - * - * Frees the ATE specified by @dma_map. - */ -void -free_pciio_dmamap(pcibr_dmamap_t dma_map) -{ - dma_map->bd_dma_addr = 0; -} - -/** - * find_sn_dma_map - find an ATE associated with @dma_addr and @busnum - * @dma_addr: DMA address to look for - * @busnum: PCI bus to look on - * - * Finds the ATE associated with @dma_addr and @busnum. - */ -static struct pcibr_dmamap_s * -find_sn_dma_map(dma_addr_t dma_addr, unsigned char busnum) -{ - - struct pcibr_dmamap_s *sn_dma_map = NULL; - int i; - - sn_dma_map = busnum_to_atedmamaps[busnum]; - - for (i = 0; i < MAX_ATE_MAPS; i++, sn_dma_map++) { - if (sn_dma_map->bd_dma_addr == dma_addr) { - return sn_dma_map; - } - } - - return NULL; -} - -/** - * sn_pci_alloc_consistent - allocate memory for coherent DMA - * @hwdev: device to allocate for - * @size: size of the region - * @dma_handle: DMA (bus) address - * - * pci_alloc_consistent() returns a pointer to a memory region suitable for - * coherent DMA traffic to/from a PCI device. On SN platforms, this means - * that @dma_handle will have the %PCIIO_DMA_CMD flag set. - * - * This interface is usually used for "command" streams (e.g. the command - * queue for a SCSI controller). See Documentation/DMA-mapping.txt for - * more information. - * - * Also known as platform_pci_alloc_consistent() by the IA64 machvec code. - */ -void * -sn_pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) -{ - void *cpuaddr; - vertex_hdl_t vhdl; - struct sn_device_sysdata *device_sysdata; - unsigned long phys_addr; - pcibr_dmamap_t dma_map = 0; - - /* - * Get hwgraph vertex for the device - */ - device_sysdata = SN_DEVICE_SYSDATA(hwdev); - vhdl = device_sysdata->vhdl; - - /* - * Allocate the memory. - * FIXME: We should be doing alloc_pages_node for the node closest - * to the PCI device. - */ - if (!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size)))) - return NULL; - - memset(cpuaddr, 0x0, size); - - /* physical addr. of the memory we just got */ - phys_addr = __pa(cpuaddr); - - /* - * 64 bit address translations should never fail. - * 32 bit translations can fail if there are insufficient mapping - * resources and the direct map is already wired to a different - * 2GB range. - * 32 bit translations can also return a > 32 bit address, because - * pcibr_dmatrans_addr ignores a missing PCIIO_DMA_A64 flag on - * PCI-X buses. - */ - if (hwdev->dev.coherent_dma_mask == ~0UL) - *dma_handle = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_DMA_CMD | PCIIO_DMA_A64); - else { - dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_CMD | - MINIMAL_ATE_FLAG(phys_addr, size)); - if (dma_map) { - *dma_handle = (dma_addr_t) - pcibr_dmamap_addr(dma_map, phys_addr, size); - dma_map->bd_dma_addr = *dma_handle; - } - else { - *dma_handle = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, - PCIIO_DMA_CMD); - } - } - - if (!*dma_handle || *dma_handle > hwdev->dev.coherent_dma_mask) { - if (dma_map) { - pcibr_dmamap_done(dma_map); - pcibr_dmamap_free(dma_map); - } - free_pages((unsigned long) cpuaddr, get_order(size)); - return NULL; - } - - return cpuaddr; -} - -/** - * sn_pci_free_consistent - free memory associated with coherent DMAable region - * @hwdev: device to free for - * @size: size to free - * @vaddr: kernel virtual address to free - * @dma_handle: DMA address associated with this region - * - * Frees the memory allocated by pci_alloc_consistent(). Also known - * as platform_pci_free_consistent() by the IA64 machvec code. - */ -void -sn_pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) -{ - struct pcibr_dmamap_s *dma_map = NULL; - - /* - * Get the sn_dma_map entry. - */ - if (IS_PCI32_MAPPED(dma_handle)) - dma_map = find_sn_dma_map(dma_handle, hwdev->bus->number); - - /* - * and free it if necessary... - */ - if (dma_map) { - pcibr_dmamap_done(dma_map); - pcibr_dmamap_free(dma_map); - } - free_pages((unsigned long) vaddr, get_order(size)); -} - -/** - * sn_pci_map_sg - map a scatter-gather list for DMA - * @hwdev: device to map for - * @sg: scatterlist to map - * @nents: number of entries - * @direction: direction of the DMA transaction - * - * Maps each entry of @sg for DMA. Also known as platform_pci_map_sg by the - * IA64 machvec code. - */ -int -sn_pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - int i; - vertex_hdl_t vhdl; - unsigned long phys_addr; - struct sn_device_sysdata *device_sysdata; - pcibr_dmamap_t dma_map; - struct scatterlist *saved_sg = sg; - unsigned dma_flag; - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - /* - * Get the hwgraph vertex for the device - */ - device_sysdata = SN_DEVICE_SYSDATA(hwdev); - vhdl = device_sysdata->vhdl; - - /* - * 64 bit DMA mask can use direct translations - * PCI only - * 32 bit DMA mask might be able to use direct, otherwise use dma map - * PCI-X - * only 64 bit DMA mask supported; both direct and dma map will fail - */ - if (hwdev->dma_mask == ~0UL) - dma_flag = PCIIO_DMA_DATA | PCIIO_DMA_A64; - else - dma_flag = PCIIO_DMA_DATA; - - /* - * Setup a DMA address for each entry in the - * scatterlist. - */ - for (i = 0; i < nents; i++, sg++) { - phys_addr = __pa((unsigned long)page_address(sg->page) + sg->offset); - sg->dma_address = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, - sg->length, dma_flag); - if (sg->dma_address) { - sg->dma_length = sg->length; - continue; - } - - dma_map = pcibr_dmamap_alloc(vhdl, NULL, sg->length, - PCIIO_DMA_DATA|MINIMAL_ATE_FLAG(phys_addr, sg->length)); - if (!dma_map) { - printk(KERN_ERR "sn_pci_map_sg: Unable to allocate " - "anymore 32 bit page map entries.\n"); - /* - * We will need to free all previously allocated entries. - */ - if (i > 0) { - sn_pci_unmap_sg(hwdev, saved_sg, i, direction); - } - return (0); - } - - sg->dma_address = pcibr_dmamap_addr(dma_map, phys_addr, sg->length); - sg->dma_length = sg->length; - dma_map->bd_dma_addr = sg->dma_address; - } - - return nents; - -} - -/** - * sn_pci_unmap_sg - unmap a scatter-gather list - * @hwdev: device to unmap - * @sg: scatterlist to unmap - * @nents: number of scatterlist entries - * @direction: DMA direction - * - * Unmap a set of streaming mode DMA translations. Again, cpu read rules - * concerning calls here are the same as for pci_unmap_single() below. Also - * known as sn_pci_unmap_sg() by the IA64 machvec code. - */ -void -sn_pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - int i; - struct pcibr_dmamap_s *dma_map; - - /* can't go anywhere w/o a direction in life */ - if (direction == PCI_DMA_NONE) - BUG(); - - for (i = 0; i < nents; i++, sg++){ - - if (IS_PCI32_MAPPED(sg->dma_address)) { - dma_map = find_sn_dma_map(sg->dma_address, hwdev->bus->number); - if (dma_map) { - pcibr_dmamap_done(dma_map); - pcibr_dmamap_free(dma_map); - } - } - - sg->dma_address = (dma_addr_t)NULL; - sg->dma_length = 0; - } -} - -/** - * sn_pci_map_single - map a single region for DMA - * @hwdev: device to map for - * @ptr: kernel virtual address of the region to map - * @size: size of the region - * @direction: DMA direction - * - * Map the region pointed to by @ptr for DMA and return the - * DMA address. Also known as platform_pci_map_single() by - * the IA64 machvec code. - * - * We map this to the one step pcibr_dmamap_trans interface rather than - * the two step pcibr_dmamap_alloc/pcibr_dmamap_addr because we have - * no way of saving the dmamap handle from the alloc to later free - * (which is pretty much unacceptable). - * - * TODO: simplify our interface; - * get rid of dev_desc and vhdl (seems redundant given a pci_dev); - * figure out how to save dmamap handle so can use two step. - */ -dma_addr_t -sn_pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - vertex_hdl_t vhdl; - dma_addr_t dma_addr; - unsigned long phys_addr; - struct sn_device_sysdata *device_sysdata; - pcibr_dmamap_t dma_map = NULL; - unsigned dma_flag; - - if (direction == PCI_DMA_NONE) - BUG(); - - /* - * find vertex for the device - */ - device_sysdata = SN_DEVICE_SYSDATA(hwdev); - vhdl = device_sysdata->vhdl; - - phys_addr = __pa(ptr); - /* - * 64 bit DMA mask can use direct translations - * PCI only - * 32 bit DMA mask might be able to use direct, otherwise use dma map - * PCI-X - * only 64 bit DMA mask supported; both direct and dma map will fail - */ - if (hwdev->dma_mask == ~0UL) - dma_flag = PCIIO_DMA_DATA | PCIIO_DMA_A64; - else - dma_flag = PCIIO_DMA_DATA; - - dma_addr = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, dma_flag); - if (dma_addr) - return dma_addr; - - /* - * It's a 32 bit card and we cannot do direct mapping so - * let's use the PMU instead. - */ - dma_map = NULL; - dma_map = pcibr_dmamap_alloc(vhdl, NULL, size, PCIIO_DMA_DATA | - MINIMAL_ATE_FLAG(phys_addr, size)); - - /* PMU out of entries */ - if (!dma_map) - return 0; - - dma_addr = (dma_addr_t) pcibr_dmamap_addr(dma_map, phys_addr, size); - dma_map->bd_dma_addr = dma_addr; - - return ((dma_addr_t)dma_addr); -} - -/** - * sn_pci_unmap_single - unmap a region used for DMA - * @hwdev: device to unmap - * @dma_addr: DMA address to unmap - * @size: size of region - * @direction: DMA direction - * - * Unmaps the region pointed to by @dma_addr. Also known as - * platform_pci_unmap_single() by the IA64 machvec code. - */ -void -sn_pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) -{ - struct pcibr_dmamap_s *dma_map = NULL; - - if (direction == PCI_DMA_NONE) - BUG(); - - /* - * Get the sn_dma_map entry. - */ - if (IS_PCI32_MAPPED(dma_addr)) - dma_map = find_sn_dma_map(dma_addr, hwdev->bus->number); - - /* - * and free it if necessary... - */ - if (dma_map) { - pcibr_dmamap_done(dma_map); - pcibr_dmamap_free(dma_map); - } -} - -/** - * sn_pci_dma_sync_single_* - make sure all DMAs or CPU accesses - * have completed - * @hwdev: device to sync - * @dma_handle: DMA address to sync - * @size: size of region - * @direction: DMA direction - * - * This routine is supposed to sync the DMA region specified - * by @dma_handle into the 'coherence domain'. We do not need to do - * anything on our platform. - */ -void -sn_pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) -{ - return; -} - -void -sn_pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) -{ - return; -} - -/** - * sn_pci_dma_sync_sg_* - make sure all DMAs or CPU accesses have completed - * @hwdev: device to sync - * @sg: scatterlist to sync - * @nents: number of entries in the scatterlist - * @direction: DMA direction - * - * This routine is supposed to sync the DMA regions specified - * by @sg into the 'coherence domain'. We do not need to do anything - * on our platform. - */ -void -sn_pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - return; -} - -void -sn_pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) -{ - return; -} - -/** - * sn_dma_supported - test a DMA mask - * @hwdev: device to test - * @mask: DMA mask to test - * - * Return whether the given PCI device DMA address mask can be supported - * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask to - * this function. Of course, SN only supports devices that have 32 or more - * address bits when using the PMU. We could theoretically support <32 bit - * cards using direct mapping, but we'll worry about that later--on the off - * chance that someone actually wants to use such a card. - */ -int -sn_pci_dma_supported(struct pci_dev *hwdev, u64 mask) -{ - if (mask < 0xffffffff) - return 0; - return 1; -} - -/* - * New generic DMA routines just wrap sn2 PCI routines until we - * support other bus types (if ever). - */ - -int -sn_dma_supported(struct device *dev, u64 mask) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_dma_supported(to_pci_dev(dev), mask); -} -EXPORT_SYMBOL(sn_dma_supported); - -int -sn_dma_set_mask(struct device *dev, u64 dma_mask) -{ - BUG_ON(dev->bus != &pci_bus_type); - - if (!sn_dma_supported(dev, dma_mask)) - return 0; - - *dev->dma_mask = dma_mask; - return 1; -} -EXPORT_SYMBOL(sn_dma_set_mask); - -void * -sn_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - int flag) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); -} -EXPORT_SYMBOL(sn_dma_alloc_coherent); - -void -sn_dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); -} -EXPORT_SYMBOL(sn_dma_free_coherent); - -dma_addr_t -sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_map_single); - -void -sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_unmap_single); - -dma_addr_t -sn_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_map_page); - -void -sn_dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_unmap_page); - -int -sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return sn_pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); -} -EXPORT_SYMBOL(sn_dma_map_sg); - -void -sn_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); -} -EXPORT_SYMBOL(sn_dma_unmap_sg); - -void -sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_sync_single_for_cpu); - -void -sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, size, (int)direction); -} -EXPORT_SYMBOL(sn_dma_sync_single_for_device); - -void -sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); -} -EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu); - -void -sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - int direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - sn_pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); -} -EXPORT_SYMBOL(sn_dma_sync_sg_for_device); - -int -sn_dma_mapping_error(dma_addr_t dma_addr) -{ - /* - * We can only run out of page mapping entries, so if there's - * an error, tell the caller to try again later. - */ - if (!dma_addr) - return -EAGAIN; - return 0; -} - -EXPORT_SYMBOL(sn_dma_mapping_error); -EXPORT_SYMBOL(sn_pci_unmap_single); -EXPORT_SYMBOL(sn_pci_map_single); -EXPORT_SYMBOL(sn_pci_dma_sync_single_for_cpu); -EXPORT_SYMBOL(sn_pci_dma_sync_single_for_device); -EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_cpu); -EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_device); -EXPORT_SYMBOL(sn_pci_map_sg); -EXPORT_SYMBOL(sn_pci_unmap_sg); -EXPORT_SYMBOL(sn_pci_alloc_consistent); -EXPORT_SYMBOL(sn_pci_free_consistent); -EXPORT_SYMBOL(sn_pci_dma_supported); - diff --git a/arch/ia64/sn/io/platform_init/Makefile b/arch/ia64/sn/io/platform_init/Makefile deleted file mode 100644 index 325208808..000000000 --- a/arch/ia64/sn/io/platform_init/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 io routines. - -obj-y += sgi_io_init.o diff --git a/arch/ia64/sn/io/platform_init/sgi_io_init.c b/arch/ia64/sn/io/platform_init/sgi_io_init.c deleted file mode 100644 index 4833cfb3b..000000000 --- a/arch/ia64/sn/io/platform_init/sgi_io_init.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void init_all_devices(void); -extern void klhwg_add_all_modules(vertex_hdl_t); -extern void klhwg_add_all_nodes(vertex_hdl_t); - -extern int init_hcl(void); -extern vertex_hdl_t hwgraph_root; -extern void io_module_init(void); -extern int pci_bus_to_hcl_cvlink(void); - -nasid_t console_nasid = (nasid_t) - 1; -char master_baseio_wid; - -nasid_t master_baseio_nasid; -nasid_t master_nasid = INVALID_NASID; /* This is the partition master nasid */ - -/* - * per_hub_init - * - * This code is executed once for each Hub chip. - */ -static void __init -per_hub_init(cnodeid_t cnode) -{ - nasid_t nasid; - nodepda_t *npdap; - ii_icmr_u_t ii_icmr; - ii_ibcr_u_t ii_ibcr; - ii_ilcsr_u_t ii_ilcsr; - - nasid = cnodeid_to_nasid(cnode); - - ASSERT(nasid != INVALID_NASID); - ASSERT(nasid_to_cnodeid(nasid) == cnode); - - npdap = NODEPDA(cnode); - - /* Disable the request and reply errors. */ - REMOTE_HUB_S(nasid, IIO_IWEIM, 0xC000); - - /* - * Set the total number of CRBs that can be used. - */ - ii_icmr.ii_icmr_regval = 0x0; - ii_icmr.ii_icmr_fld_s.i_c_cnt = 0xf; - if (enable_shub_wars_1_1()) { - // Set bit one of ICMR to prevent II from sending interrupt for II bug. - ii_icmr.ii_icmr_regval |= 0x1; - } - REMOTE_HUB_S(nasid, IIO_ICMR, ii_icmr.ii_icmr_regval); - - /* - * Set the number of CRBs that both of the BTEs combined - * can use minus 1. - */ - ii_ibcr.ii_ibcr_regval = 0x0; - ii_ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - if (ii_ilcsr.ii_ilcsr_fld_s.i_llp_stat & LNK_STAT_WORKING) { - ii_ibcr.ii_ibcr_fld_s.i_count = 0x8; - } else { - /* - * if the LLP is down, there is no attached I/O, so - * give BTE all the CRBs. - */ - ii_ibcr.ii_ibcr_fld_s.i_count = 0x14; - } - REMOTE_HUB_S(nasid, IIO_IBCR, ii_ibcr.ii_ibcr_regval); - - /* - * Set CRB timeout to be 10ms. - */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0xffffff); - REMOTE_HUB_S(nasid, IIO_ICTO, 0xff); - - /* Initialize error interrupts for this hub. */ - hub_error_init(cnode); -} - -/* - * This routine is responsible for the setup of all the IRIX hwgraph style - * stuff that's been pulled into linux. It's called by sn_pci_find_bios which - * is called just before the generic Linux PCI layer does its probing (by - * platform_pci_fixup aka sn_pci_fixup). - * - * It is very IMPORTANT that this call is only made by the Master CPU! - * - */ - -void __init -sgi_master_io_infr_init(void) -{ - cnodeid_t cnode; - - if (init_hcl() < 0) { /* Sets up the hwgraph compatibility layer */ - printk("sgi_master_io_infr_init: Cannot init hcl\n"); - return; - } - - /* - * Initialize platform-dependent vertices in the hwgraph: - * module - * node - * cpu - * memory - * slot - * hub - * router - * xbow - */ - - io_module_init(); /* Use to be called module_init() .. */ - klhwg_add_all_modules(hwgraph_root); - klhwg_add_all_nodes(hwgraph_root); - - for (cnode = 0; cnode < numionodes; cnode++) - per_hub_init(cnode); - - /* - * - * Our IO Infrastructure drivers are in place .. - * Initialize the whole IO Infrastructure .. xwidget/device probes. - * - */ - init_all_devices(); - pci_bus_to_hcl_cvlink(); -} - -inline int -check_nasid_equiv(nasid_t nasida, nasid_t nasidb) -{ - if ((nasida == nasidb) - || (nasida == NODEPDA(nasid_to_cnodeid(nasidb))->xbow_peer)) - return 1; - else - return 0; -} - -int -is_master_baseio_nasid_widget(nasid_t test_nasid, xwidgetnum_t test_wid) -{ - /* - * If the widget numbers are different, we're not the master. - */ - if (test_wid != (xwidgetnum_t) master_baseio_wid) { - return 0; - } - - /* - * If the NASIDs are the same or equivalent, we're the master. - */ - if (check_nasid_equiv(test_nasid, master_baseio_nasid)) { - return 1; - } else { - return 0; - } -} diff --git a/arch/ia64/sn/io/sn2/Makefile b/arch/ia64/sn/io/sn2/Makefile deleted file mode 100644 index 45779e215..000000000 --- a/arch/ia64/sn/io/sn2/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# arch/ia64/sn/io/sn2/Makefile -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 specific io routines. -# - -obj-y += pcibr/ ml_SN_intr.o shub_intr.o shuberror.o shub.o bte_error.o \ - pic.o geo_op.o l1_command.o klconflib.o klgraph.o ml_SN_init.o \ - ml_iograph.o module.o pciio.o xbow.o xtalk.o shubio.o diff --git a/arch/ia64/sn/io/sn2/bte_error.c b/arch/ia64/sn/io/sn2/bte_error.c deleted file mode 100644 index b77e9e2df..000000000 --- a/arch/ia64/sn/io/sn2/bte_error.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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. - * - * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Bte error handling is done in two parts. The first captures - * any crb related errors. Since there can be multiple crbs per - * interface and multiple interfaces active, we need to wait until - * all active crbs are completed. This is the first job of the - * second part error handler. When all bte related CRBs are cleanly - * completed, it resets the interfaces and gets them ready for new - * transfers to be queued. - */ - - -void bte_error_handler(unsigned long); - - -/* - * First part error handler. This is called whenever any error CRB interrupt - * is generated by the II. - */ -void -bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, - int crbnum, ioerror_t * ioe, int bteop) -{ - hubinfo_t hinfo; - struct bteinfo_s *bte; - - - hubinfo_get(hub_v, &hinfo); - bte = &hinfo->h_nodepda->bte_if[btenum]; - - /* - * The caller has already figured out the error type, we save that - * in the bte handle structure for the thread excercising the - * interface to consume. - */ - bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET; - bte->bte_error_count++; - - BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n", - bte->bte_cnode, bte->bte_num, ioe->ie_errortype)); - bte_error_handler((unsigned long) hinfo->h_nodepda); -} - - -/* - * Second part error handler. Wait until all BTE related CRBs are completed - * and then reset the interfaces. - */ -void -bte_error_handler(unsigned long _nodepda) -{ - struct nodepda_s *err_nodepda = (struct nodepda_s *) _nodepda; - spinlock_t *recovery_lock = &err_nodepda->bte_recovery_lock; - struct timer_list *recovery_timer = &err_nodepda->bte_recovery_timer; - nasid_t nasid; - int i; - int valid_crbs; - unsigned long irq_flags; - volatile u64 *notify; - bte_result_t bh_error; - ii_imem_u_t imem; /* II IMEM Register */ - ii_icrb0_d_u_t icrbd; /* II CRB Register D */ - ii_ibcr_u_t ibcr; - ii_icmr_u_t icmr; - ii_ieclr_u_t ieclr; - - - BTE_PRINTK(("bte_error_handler(%p) - %d\n", err_nodepda, - smp_processor_id())); - - spin_lock_irqsave(recovery_lock, irq_flags); - - if ((err_nodepda->bte_if[0].bh_error == BTE_SUCCESS) && - (err_nodepda->bte_if[1].bh_error == BTE_SUCCESS)) { - BTE_PRINTK(("eh:%p:%d Nothing to do.\n", err_nodepda, - smp_processor_id())); - spin_unlock_irqrestore(recovery_lock, irq_flags); - return; - } - /* - * Lock all interfaces on this node to prevent new transfers - * from being queued. - */ - for (i = 0; i < BTES_PER_NODE; i++) { - if (err_nodepda->bte_if[i].cleanup_active) { - continue; - } - spin_lock(&err_nodepda->bte_if[i].spinlock); - BTE_PRINTK(("eh:%p:%d locked %d\n", err_nodepda, - smp_processor_id(), i)); - err_nodepda->bte_if[i].cleanup_active = 1; - } - - /* Determine information about our hub */ - nasid = cnodeid_to_nasid(err_nodepda->bte_if[0].bte_cnode); - - - /* - * A BTE transfer can use multiple CRBs. We need to make sure - * that all the BTE CRBs are complete (or timed out) before - * attempting to clean up the error. Resetting the BTE while - * there are still BTE CRBs active will hang the BTE. - * We should look at all the CRBs to see if they are allocated - * to the BTE and see if they are still active. When none - * are active, we can continue with the cleanup. - * - * We also want to make sure that the local NI port is up. - * When a router resets the NI port can go down, while it - * goes through the LLP handshake, but then comes back up. - */ - icmr.ii_icmr_regval = REMOTE_HUB_L(nasid, IIO_ICMR); - if (icmr.ii_icmr_fld_s.i_crb_mark != 0) { - /* - * There are errors which still need to be cleaned up by - * hubiio_crb_error_handler - */ - mod_timer(recovery_timer, HZ * 5); - BTE_PRINTK(("eh:%p:%d Marked Giving up\n", err_nodepda, - smp_processor_id())); - spin_unlock_irqrestore(recovery_lock, irq_flags); - return; - } - if (icmr.ii_icmr_fld_s.i_crb_vld != 0) { - - valid_crbs = icmr.ii_icmr_fld_s.i_crb_vld; - - for (i = 0; i < IIO_NUM_CRBS; i++) { - if (!((1 << i) & valid_crbs)) { - /* This crb was not marked as valid, ignore */ - continue; - } - icrbd.ii_icrb0_d_regval = - REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); - if (icrbd.d_bteop) { - mod_timer(recovery_timer, HZ * 5); - BTE_PRINTK(("eh:%p:%d Valid %d, Giving up\n", - err_nodepda, smp_processor_id(), i)); - spin_unlock_irqrestore(recovery_lock, - irq_flags); - return; - } - } - } - - - BTE_PRINTK(("eh:%p:%d Cleaning up\n", err_nodepda, - smp_processor_id())); - /* Reenable both bte interfaces */ - imem.ii_imem_regval = REMOTE_HUB_L(nasid, IIO_IMEM); - imem.ii_imem_fld_s.i_b0_esd = imem.ii_imem_fld_s.i_b1_esd = 1; - REMOTE_HUB_S(nasid, IIO_IMEM, imem.ii_imem_regval); - - /* Clear IBLS0/1 error bits */ - ieclr.ii_ieclr_regval = 0; - if (err_nodepda->bte_if[0].bh_error != BTE_SUCCESS) - ieclr.ii_ieclr_fld_s.i_e_bte_0 = 1; - if (err_nodepda->bte_if[1].bh_error != BTE_SUCCESS) - ieclr.ii_ieclr_fld_s.i_e_bte_1 = 1; - REMOTE_HUB_S(nasid, IIO_IECLR, ieclr.ii_ieclr_regval); - - /* Reinitialize both BTE state machines. */ - ibcr.ii_ibcr_regval = REMOTE_HUB_L(nasid, IIO_IBCR); - ibcr.ii_ibcr_fld_s.i_soft_reset = 1; - REMOTE_HUB_S(nasid, IIO_IBCR, ibcr.ii_ibcr_regval); - - - for (i = 0; i < BTES_PER_NODE; i++) { - bh_error = err_nodepda->bte_if[i].bh_error; - if (bh_error != BTE_SUCCESS) { - /* There is an error which needs to be notified */ - notify = err_nodepda->bte_if[i].most_rcnt_na; - BTE_PRINTK(("cnode %d bte %d error=0x%lx\n", - err_nodepda->bte_if[i].bte_cnode, - err_nodepda->bte_if[i].bte_num, - IBLS_ERROR | (u64) bh_error)); - *notify = IBLS_ERROR | bh_error; - err_nodepda->bte_if[i].bh_error = BTE_SUCCESS; - } - - err_nodepda->bte_if[i].cleanup_active = 0; - BTE_PRINTK(("eh:%p:%d Unlocked %d\n", err_nodepda, - smp_processor_id(), i)); - spin_unlock(&err_nodepda->bte_if[i].spinlock); - } - - del_timer(recovery_timer); - - spin_unlock_irqrestore(recovery_lock, irq_flags); -} diff --git a/arch/ia64/sn/io/sn2/geo_op.c b/arch/ia64/sn/io/sn2/geo_op.c deleted file mode 100644 index da46a15f8..000000000 --- a/arch/ia64/sn/io/sn2/geo_op.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * @doc file m:hwcfg - * DESCRIPTION: - * - * This file contains routines for manipulating and generating - * Geographic IDs. They are in a file by themself since they have - * no dependencies on other modules. - * - * ORIGIN: - * - * New for SN2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/********** Global functions and data (visible outside the module) ***********/ - -/* - * @doc gf:geo_module - * - * moduleid_t geo_module(geoid_t g) - * - * DESCRIPTION: - * - * Return the moduleid component of a geoid. - * - * INTERNALS: - * - * Return INVALID_MODULE for an invalid geoid. Otherwise extract the - * moduleid from the structure, and return it. - * - * ORIGIN: - * - * New for SN2 - */ - -moduleid_t -geo_module(geoid_t g) -{ - if (g.any.type == GEO_TYPE_INVALID) - return INVALID_MODULE; - else - return g.any.module; -} - - -/* - * @doc gf:geo_slab - * - * slabid_t geo_slab(geoid_t g) - * - * DESCRIPTION: - * - * Return the slabid component of a geoid. - * - * INTERNALS: - * - * Return INVALID_SLAB for an invalid geoid. Otherwise extract the - * slabid from the structure, and return it. - * - * ORIGIN: - * - * New for SN2 - */ - -slabid_t -geo_slab(geoid_t g) -{ - if (g.any.type == GEO_TYPE_INVALID) - return INVALID_SLAB; - else - return g.any.slab; -} - - -/* - * @doc gf:geo_type - * - * geo_type_t geo_type(geoid_t g) - * - * DESCRIPTION: - * - * Return the type component of a geoid. - * - * INTERNALS: - * - * Extract the type from the structure, and return it. - * - * ORIGIN: - * - * New for SN2 - */ - -geo_type_t -geo_type(geoid_t g) -{ - return g.any.type; -} - - -/* - * @doc gf:geo_valid - * - * int geo_valid(geoid_t g) - * - * DESCRIPTION: - * - * Return nonzero if g has a valid geoid type. - * - * INTERNALS: - * - * Test the type against GEO_TYPE_INVALID, and return the result. - * - * ORIGIN: - * - * New for SN2 - */ - -int -geo_valid(geoid_t g) -{ - return g.any.type != GEO_TYPE_INVALID; -} - - -/* - * @doc gf:geo_cmp - * - * int geo_cmp(geoid_t g0, geoid_t g1) - * - * DESCRIPTION: - * - * Compare two geoid_t values, from the coarsest field to the finest. - * The comparison should be consistent with the physical locations of - * of the hardware named by the geoids. - * - * INTERNALS: - * - * First compare the module, then the slab, type, and type-specific fields. - * - * ORIGIN: - * - * New for SN2 - */ - -int -geo_cmp(geoid_t g0, geoid_t g1) -{ - int rv; - - /* Compare the common fields */ - rv = MODULE_CMP(geo_module(g0), geo_module(g1)); - if (rv != 0) - return rv; - - rv = geo_slab(g0) - geo_slab(g1); - if (rv != 0) - return rv; - - /* Within a slab, sort by type */ - rv = geo_type(g0) - geo_type(g1); - if (rv != 0) - return rv; - - switch(geo_type(g0)) { - case GEO_TYPE_CPU: - rv = g0.cpu.slice - g1.cpu.slice; - break; - - case GEO_TYPE_IOCARD: - rv = g0.pcicard.bus - g1.pcicard.bus; - if (rv) break; - rv = SLOTNUM_GETSLOT(g0.pcicard.slot) - - SLOTNUM_GETSLOT(g1.pcicard.slot); - break; - - case GEO_TYPE_MEM: - rv = g0.mem.membus - g1.mem.membus; - if (rv) break; - rv = g0.mem.memslot - g1.mem.memslot; - break; - - default: - rv = 0; - } - - return rv; -} - - -/* - * @doc gf:geo_new - * - * geoid_t geo_new(geo_type_t type, ...) - * - * DESCRIPTION: - * - * Generate a new geoid_t value of the given type from its components. - * Expected calling sequences: - * \@itemize \@bullet - * \@item - * \@code\{geo_new(GEO_TYPE_INVALID)\} - * \@item - * \@code\{geo_new(GEO_TYPE_MODULE, moduleid_t m)\} - * \@item - * \@code\{geo_new(GEO_TYPE_NODE, moduleid_t m, slabid_t s)\} - * \@item - * \@code\{geo_new(GEO_TYPE_RTR, moduleid_t m, slabid_t s)\} - * \@item - * \@code\{geo_new(GEO_TYPE_IOCNTL, moduleid_t m, slabid_t s)\} - * \@item - * \@code\{geo_new(GEO_TYPE_IOCARD, moduleid_t m, slabid_t s, char bus, slotid_t slot)\} - * \@item - * \@code\{geo_new(GEO_TYPE_CPU, moduleid_t m, slabid_t s, char slice)\} - * \@item - * \@code\{geo_new(GEO_TYPE_MEM, moduleid_t m, slabid_t s, char membus, char slot)\} - * \@end itemize - * - * Invalid types return a GEO_TYPE_INVALID geoid_t. - * - * INTERNALS: - * - * Use the type to determine which fields to expect. Write the fields into - * a new geoid_t and return it. Note: scalars smaller than an "int" are - * promoted to "int" by the "..." operator, so we need extra casts on "char", - * "slotid_t", and "slabid_t". - * - * ORIGIN: - * - * New for SN2 - */ - -geoid_t -geo_new(geo_type_t type, ...) -{ - va_list al; - geoid_t g; - memset(&g, 0, sizeof(g)); - - va_start(al, type); - - /* Make sure the type is sane */ - if (type >= GEO_TYPE_MAX) - type = GEO_TYPE_INVALID; - - g.any.type = type; - if (type == GEO_TYPE_INVALID) - goto done; /* invalid geoids have no components at all */ - - g.any.module = va_arg(al, moduleid_t); - if (type == GEO_TYPE_MODULE) - goto done; - - g.any.slab = (slabid_t)va_arg(al, int); - - /* Some types have additional components */ - switch(type) { - case GEO_TYPE_CPU: - g.cpu.slice = (char)va_arg(al, int); - break; - - case GEO_TYPE_IOCARD: - g.pcicard.bus = (char)va_arg(al, int); - g.pcicard.slot = (slotid_t)va_arg(al, int); - break; - - case GEO_TYPE_MEM: - g.mem.membus = (char)va_arg(al, int); - g.mem.memslot = (char)va_arg(al, int); - break; - - default: - break; - } - - done: - va_end(al); - return g; -} diff --git a/arch/ia64/sn/io/sn2/klconflib.c b/arch/ia64/sn/io/sn2/klconflib.c deleted file mode 100644 index e4edb7ca0..000000000 --- a/arch/ia64/sn/io/sn2/klconflib.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#undef DEBUG_KLGRAPH -#ifdef DEBUG_KLGRAPH -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* DEBUG_KLGRAPH */ - -extern int numionodes; - -lboard_t *root_lboard[MAX_COMPACT_NODES]; -static int hasmetarouter; - - -char brick_types[MAX_BRICK_TYPES + 1] = "crikxdpn%#=vo^34567890123456789..."; - -lboard_t * -find_lboard_any(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (start->brd_type == brd_type) - return start; - start = KLCF_NEXT_ANY(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_nasid(lboard_t *start, nasid_t nasid, unsigned char brd_type) -{ - - while (start) { - if ((start->brd_type == brd_type) && - (start->brd_nasid == nasid)) - return start; - - if (numionodes == numnodes) - start = KLCF_NEXT_ANY(start); - else - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_class_any(lboard_t *start, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) - return start; - start = KLCF_NEXT_ANY(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -lboard_t * -find_lboard_class_nasid(lboard_t *start, nasid_t nasid, unsigned char brd_type) -{ - /* Search all boards stored on this node. */ - while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type) && - (start->brd_nasid == nasid)) - return start; - - if (numionodes == numnodes) - start = KLCF_NEXT_ANY(start); - else - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - - - -klinfo_t * -find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) -{ - int index, j; - - if (kli == (klinfo_t *)NULL) { - index = 0; - } else { - for (j = 0; j < KLCF_NUM_COMPS(brd); j++) { - if (kli == KLCF_COMP(brd, j)) - break; - } - index = j; - if (index == KLCF_NUM_COMPS(brd)) { - DBG("find_component: Bad pointer: 0x%p\n", kli); - return (klinfo_t *)NULL; - } - index++; /* next component */ - } - - for (; index < KLCF_NUM_COMPS(brd); index++) { - kli = KLCF_COMP(brd, index); - DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli)); - if (KLCF_COMP_TYPE(kli) == struct_type) - return kli; - } - - /* Didn't find it. */ - return (klinfo_t *)NULL; -} - -klinfo_t * -find_first_component(lboard_t *brd, unsigned char struct_type) -{ - return find_component(brd, (klinfo_t *)NULL, struct_type); -} - -lboard_t * -find_lboard_modslot(lboard_t *start, geoid_t geoid) -{ - /* Search all boards stored on this node. */ - while (start) { - if (geo_cmp(start->brd_geoid, geoid)) - return start; - start = KLCF_NEXT(start); - } - - /* Didn't find it. */ - return (lboard_t *)NULL; -} - -/* - * Convert a NIC name to a name for use in the hardware graph. - */ -void -nic_name_convert(char *old_name, char *new_name) -{ - int i; - char c; - char *compare_ptr; - - if ((old_name[0] == '\0') || (old_name[1] == '\0')) { - strcpy(new_name, EDGE_LBL_XWIDGET); - } else { - for (i = 0; i < strlen(old_name); i++) { - c = old_name[i]; - - if (isalpha(c)) - new_name[i] = tolower(c); - else if (isdigit(c)) - new_name[i] = c; - else - new_name[i] = '_'; - } - new_name[i] = '\0'; - } - - /* XXX - - * Since a bunch of boards made it out with weird names like - * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and - * replace it with "baseio" to avoid confusion in the field. - * We also have to make sure we don't report media_io instead of - * baseio. - */ - - /* Skip underscores at the beginning of the name */ - for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++) - ; - - /* - * Check for some names we need to replace. Early boards - * had junk following the name so check only the first - * characters. - */ - if (!strncmp(new_name, "io6", 3) || - !strncmp(new_name, "mio", 3) || - !strncmp(new_name, "media_io", 8)) - strcpy(new_name, "baseio"); - else if (!strncmp(new_name, "divo", 4)) - strcpy(new_name, "divo") ; - -} - -/* - * get_actual_nasid - * - * Completely disabled brds have their klconfig on - * some other nasid as they have no memory. But their - * actual nasid is hidden in the klconfig. Use this - * routine to get it. Works for normal boards too. - */ -nasid_t -get_actual_nasid(lboard_t *brd) -{ - klhub_t *hub ; - - if (!brd) - return INVALID_NASID ; - - /* find out if we are a completely disabled brd. */ - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - if (!hub) - return INVALID_NASID ; - if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ - return hub->hub_info.physid ; - else - return brd->brd_nasid ; -} - -int -xbow_port_io_enabled(nasid_t nasid, int link) -{ - lboard_t *brd; - klxbow_t *xbow_p; - - /* - * look for boards that might contain an xbow or xbridge - */ - brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid), nasid, KLTYPE_IOBRICK_XBOW); - if (brd == NULL) return 0; - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return 0; - - if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link)) - return 0; - - return 1; -} - -void -board_to_path(lboard_t *brd, char *path) -{ - moduleid_t modnum; - char *board_name; - char buffer[16]; - - ASSERT(brd); - - switch (KLCLASS(brd->brd_type)) { - - case KLCLASS_NODE: - board_name = EDGE_LBL_NODE; - break; - case KLCLASS_ROUTER: - if (brd->brd_type == KLTYPE_META_ROUTER) { - board_name = EDGE_LBL_META_ROUTER; - hasmetarouter++; - } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) { - board_name = EDGE_LBL_REPEATER_ROUTER; - hasmetarouter++; - } else - board_name = EDGE_LBL_ROUTER; - break; - case KLCLASS_MIDPLANE: - board_name = EDGE_LBL_MIDPLANE; - break; - case KLCLASS_IO: - board_name = EDGE_LBL_IO; - break; - case KLCLASS_IOBRICK: - if (brd->brd_type == KLTYPE_PXBRICK) - board_name = EDGE_LBL_PXBRICK; - else if (brd->brd_type == KLTYPE_IXBRICK) - board_name = EDGE_LBL_IXBRICK; - else if (brd->brd_type == KLTYPE_OPUSBRICK) - board_name = EDGE_LBL_OPUSBRICK; - else if (brd->brd_type == KLTYPE_CGBRICK) - board_name = EDGE_LBL_CGBRICK; - else - board_name = EDGE_LBL_IOBRICK; - break; - default: - board_name = EDGE_LBL_UNKNOWN; - } - - modnum = geo_module(brd->brd_geoid); - memset(buffer, 0, 16); - format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF); - sprintf(path, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/%s", buffer, geo_slab(brd->brd_geoid), board_name); -} - -#define MHZ 1000000 - -/* - * Get the serial number of the main component of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - * Assumptions: Nic manufacturing string has the following format - * *Serial:;* - */ -static int -component_serial_number_get(lboard_t *board, - klconf_off_t mfg_nic_offset, - char *serial_number, - char *key_pattern) -{ - - char *mfg_nic_string; - char *serial_string,*str; - int i; - char *serial_pattern = "Serial:"; - - /* We have an error on a null mfg nic offset */ - if (!mfg_nic_offset) - return(1); - /* Get the hub's manufacturing nic information - * which is in the form of a pre-formatted string - */ - mfg_nic_string = - (char *)NODE_OFFSET_TO_K0(NASID_GET(board), - mfg_nic_offset); - /* There is no manufacturing nic info */ - if (!mfg_nic_string) - return(1); - - str = mfg_nic_string; - /* Look for the key pattern first (if it is specified) - * and then print the serial number corresponding to that. - */ - if (strcmp(key_pattern,"") && - !(str = strstr(mfg_nic_string,key_pattern))) - return(1); - - /* There is no serial number info in the manufacturing - * nic info - */ - if (!(serial_string = strstr(str,serial_pattern))) - return(1); - - serial_string = serial_string + strlen(serial_pattern); - /* Copy the serial number information from the klconfig */ - i = 0; - while (serial_string[i] != ';') { - serial_number[i] = serial_string[i]; - i++; - } - serial_number[i] = 0; - - return(0); -} -/* - * Get the serial number of a board - * Returns 0 if a valid serial number is found - * 1 otherwise. - */ - -int -board_serial_number_get(lboard_t *board,char *serial_number) -{ - ASSERT(board && serial_number); - if (!board || !serial_number) - return(1); - - strcpy(serial_number,""); - switch(KLCLASS(board->brd_type)) { - case KLCLASS_CPU: { /* Node board */ - klhub_t *hub; - - /* Get the hub component information */ - hub = (klhub_t *)find_first_component(board, - KLSTRUCT_HUB); - /* If we don't have a hub component on an IP27 - * then we have a weird klconfig. - */ - if (!hub) - return(1); - /* Get the serial number information from - * the hub's manufacturing nic info - */ - if (component_serial_number_get(board, - hub->hub_mfg_nic, - serial_number, - "IP37")) - return(1); - break; - } - case KLCLASS_IO: { /* IO board */ - klbri_t *bridge; - - /* Get the bridge component information */ - bridge = (klbri_t *)find_first_component(board, - KLSTRUCT_BRI); - /* If we don't have a bridge component on an IO board - * then we have a weird klconfig. - */ - if (!bridge) - return(1); - /* Get the serial number information from - * the bridge's manufacturing nic info - */ - if (component_serial_number_get(board, - bridge->bri_mfg_nic, - serial_number, "")) - return(1); - break; - } - case KLCLASS_ROUTER: { /* Router board */ - klrou_t *router; - - /* Get the router component information */ - router = (klrou_t *)find_first_component(board, - KLSTRUCT_ROU); - /* If we don't have a router component on a router board - * then we have a weird klconfig. - */ - if (!router) - return(1); - /* Get the serial number information from - * the router's manufacturing nic info - */ - if (component_serial_number_get(board, - router->rou_mfg_nic, - serial_number, - "")) - return(1); - break; - } - case KLCLASS_GFX: { /* Gfx board */ - klgfx_t *graphics; - - /* Get the graphics component information */ - graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX); - /* If we don't have a gfx component on a gfx board - * then we have a weird klconfig. - */ - if (!graphics) - return(1); - /* Get the serial number information from - * the graphics's manufacturing nic info - */ - if (component_serial_number_get(board, - graphics->gfx_mfg_nic, - serial_number, - "")) - return(1); - break; - } - default: - strcpy(serial_number,""); - break; - } - return(0); -} - -/* - * Format a module id for printing. - * - * There are three possible formats: - * - * MODULE_FORMAT_BRIEF is the brief 6-character format, including - * the actual brick-type as recorded in the - * moduleid_t, eg. 002c15 for a C-brick, or - * 101#17 for a PX-brick. - * - * MODULE_FORMAT_LONG is the hwgraph format, eg. rack/002/bay/15 - * of rack/101/bay/17 (note that the brick - * type does not appear in this format). - * - * MODULE_FORMAT_LCD is like MODULE_FORMAT_BRIEF, except that it - * ensures that the module id provided appears - * exactly as it would on the LCD display of - * the corresponding brick, eg. still 002c15 - * for a C-brick, but 101p17 for a PX-brick. - */ -void -format_module_id(char *buffer, moduleid_t m, int fmt) -{ - int rack, position; - unsigned char brickchar; - - rack = MODULE_GET_RACK(m); - ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES); - brickchar = MODULE_GET_BTCHAR(m); - - if (fmt == MODULE_FORMAT_LCD) { - /* Be sure we use the same brick type character as displayed - * on the brick's LCD - */ - switch (brickchar) - { - case L1_BRICKTYPE_PX: - brickchar = L1_BRICKTYPE_P; - break; - - case L1_BRICKTYPE_IX: - brickchar = L1_BRICKTYPE_I; - break; - } - } - - position = MODULE_GET_BPOS(m); - - if ((fmt == MODULE_FORMAT_BRIEF) || (fmt == MODULE_FORMAT_LCD)) { - /* Brief module number format, eg. 002c15 */ - - /* Decompress the rack number */ - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - /* Add the brick type */ - *buffer++ = brickchar; - } - else if (fmt == MODULE_FORMAT_LONG) { - /* Fuller hwgraph format, eg. rack/002/bay/15 */ - - strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer); - - *buffer++ = '0' + RACK_GET_CLASS(rack); - *buffer++ = '0' + RACK_GET_GROUP(rack); - *buffer++ = '0' + RACK_GET_NUM(rack); - - strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer); - } - - /* Add the bay position, using at least two digits */ - if (position < 10) - *buffer++ = '0'; - sprintf(buffer, "%d", position); - -} - -int -cbrick_type_get_nasid(nasid_t nasid) -{ - moduleid_t module; - int t; - - module = iomoduleid_get(nasid); - if (module < 0 ) { - return MODULE_CBRICK; - } - t = MODULE_GET_BTYPE(module); - if ((char)t == 'o') { - return MODULE_OPUSBRICK; - } else { - return MODULE_CBRICK; - } - return -1; -} diff --git a/arch/ia64/sn/io/sn2/klgraph.c b/arch/ia64/sn/io/sn2/klgraph.c deleted file mode 100644 index 4fdffb877..000000000 --- a/arch/ia64/sn/io/sn2/klgraph.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -/* - * klgraph.c- - * This file specifies the interface between the kernel and the PROM's - * configuration data structures. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define KLGRAPH_DEBUG 1 */ -#ifdef KLGRAPH_DEBUG -#define GRPRINTF(x) printk x -#else -#define GRPRINTF(x) -#endif - -void mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid); - - -/* ARGSUSED */ -static void __init -klhwg_add_hub(vertex_hdl_t node_vertex, klhub_t *hub, cnodeid_t cnode) -{ - vertex_hdl_t myhubv; - vertex_hdl_t hub_mon; - int rc; - extern struct file_operations shub_mon_fops; - - hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, myhubv, NULL, "Created path for hub vertex for Shub node.\n"); - - rc = device_master_set(myhubv, node_vertex); - if (rc) { - printk("klhwg_add_hub: Unable to create hub vertex.\n"); - return; - } - hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON, - 0, 0, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - &shub_mon_fops, (void *)(long)cnode); -} - -/* ARGSUSED */ -static void __init -klhwg_add_disabled_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot) -{ - vertex_hdl_t my_cpu; - char name[120]; - cpuid_t cpu_id; - nasid_t nasid; - - nasid = cnodeid_to_nasid(cnode); - cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); - if(cpu_id != -1){ - snprintf(name, 120, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid); - (void) hwgraph_path_add(node_vertex, name, &my_cpu); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for disabled cpu slice.\n"); - - mark_cpuvertex_as_cpu(my_cpu, cpu_id); - device_master_set(my_cpu, node_vertex); - return; - } -} - -/* ARGSUSED */ -static void __init -klhwg_add_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu) -{ - vertex_hdl_t my_cpu, cpu_dir; - char name[120]; - cpuid_t cpu_id; - nasid_t nasid; - - nasid = cnodeid_to_nasid(cnode); - cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid); - - snprintf(name, 120, "%s/%d/%c", - EDGE_LBL_CPUBUS, - 0, - 'a' + cpu->cpu_info.physid); - - (void) hwgraph_path_add(node_vertex, name, &my_cpu); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for active cpu slice.\n"); - - mark_cpuvertex_as_cpu(my_cpu, cpu_id); - device_master_set(my_cpu, node_vertex); - - /* Add an alias under the node's CPU directory */ - if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) { - snprintf(name, 120, "%c", 'a' + cpu->cpu_info.physid); - (void) hwgraph_edge_add(cpu_dir, my_cpu, name); - HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, cpu_dir, my_cpu, "Created % from vhdl1 to vhdl2.\n", name); - } -} - - -static void __init -klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid) -{ - lboard_t *brd; - klxbow_t *xbow_p; - nasid_t hub_nasid; - cnodeid_t hub_cnode; - int widgetnum; - vertex_hdl_t xbow_v, hubv; - /*REFERENCED*/ - graph_error_t err; - - if (!(brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid), - nasid, KLTYPE_IOBRICK_XBOW))) - return; - - if (KL_CONFIG_DUPLICATE_BOARD(brd)) - return; - - if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW)) - == NULL) - return; - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) - continue; - - hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum); - if (hub_nasid == INVALID_NASID) { - printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum); - continue; - } - - hub_cnode = nasid_to_cnodeid(hub_nasid); - - if (hub_cnode == INVALID_CNODEID) { - continue; - } - - hubv = cnodeid_to_vertex(hub_cnode); - - err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v); - if (err != GRAPH_SUCCESS) { - if (err == GRAPH_DUP) - printk(KERN_WARNING "klhwg_add_xbow: Check for " - "working routers and router links!"); - - printk("klhwg_add_xbow: Failed to add " - "edge: vertex 0x%p to vertex 0x%p," - "error %d\n", - (void *)hubv, (void *)xbow_v, err); - return; - } - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, xbow_v, NULL, "Created path for xtalk.\n"); - - xswitch_vertex_init(xbow_v); - - NODEPDA(hub_cnode)->xbow_vhdl = xbow_v; - - /* - * XXX - This won't work is we ever hook up two hubs - * by crosstown through a crossbow. - */ - if (hub_nasid != nasid) { - NODEPDA(hub_cnode)->xbow_peer = nasid; - NODEPDA(nasid_to_cnodeid(nasid))->xbow_peer = - hub_nasid; - } - } -} - - -/* ARGSUSED */ -static void __init -klhwg_add_node(vertex_hdl_t hwgraph_root, cnodeid_t cnode) -{ - nasid_t nasid; - lboard_t *brd; - klhub_t *hub; - vertex_hdl_t node_vertex = NULL; - char path_buffer[100]; - int rv; - char *s; - int board_disabled = 0; - klcpu_t *cpu; - vertex_hdl_t cpu_dir; - - nasid = cnodeid_to_nasid(cnode); - brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - ASSERT(brd); - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - if (rv != GRAPH_SUCCESS) { - printk("Node vertex creation failed. Path == %s", path_buffer); - return; - } - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created path for SHUB node.\n"); - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - if(hub->hub_info.flags & KLINFO_ENABLE) - board_disabled = 0; - else - board_disabled = 1; - - if(!board_disabled) { - mark_nodevertex_as_node(node_vertex, cnode); - s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer)); - NODEPDA(cnode)->hwg_node_name = - kmalloc(strlen(s) + 1, GFP_KERNEL); - if (NODEPDA(cnode)->hwg_node_name <= 0) { - printk("%s: no memory\n", __FUNCTION__); - return; - } - strcpy(NODEPDA(cnode)->hwg_node_name, s); - hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo); - NODEPDA(cnode)->slotdesc = brd->brd_slot; - NODEPDA(cnode)->geoid = brd->brd_geoid; - NODEPDA(cnode)->module = module_lookup(geo_module(brd->brd_geoid)); - klhwg_add_hub(node_vertex, hub, cnode); - } - - /* - * If there's at least 1 CPU, add a "cpu" directory to represent - * the collection of all CPUs attached to this node. - */ - cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); - if (cpu) { - graph_error_t rv; - - rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir); - if (rv != GRAPH_SUCCESS) { - printk("klhwg_add_node: Cannot create CPU directory\n"); - return; - } - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, cpu_dir, NULL, "Created cpu directiry on SHUB node.\n"); - - } - - while (cpu) { - cpuid_t cpu_id; - cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid); - if (cpu_online(cpu_id)) - klhwg_add_cpu(node_vertex, cnode, cpu); - else - klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot); - - cpu = (klcpu_t *) - find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU); - } -} - - -/* ARGSUSED */ -static void __init -klhwg_add_all_routers(vertex_hdl_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - vertex_hdl_t node_vertex; - char path_buffer[100]; - int rv; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = cnodeid_to_nasid(cnode); - brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - /* No routers stored in this node's memory */ - continue; - - do { - ASSERT(brd); - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) - continue; - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - /* Add the router */ - rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex); - if (rv != GRAPH_SUCCESS) { - printk("Router vertex creation " - "failed. Path == %s", path_buffer); - return; - } - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created router path.\n"); - - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), - KLTYPE_ROUTER)) ); - } - -} - -/* ARGSUSED */ -static void __init -klhwg_connect_one_router(vertex_hdl_t hwgraph_root, lboard_t *brd, - cnodeid_t cnode, nasid_t nasid) -{ - klrou_t *router; - char path_buffer[50]; - char dest_path[50]; - vertex_hdl_t router_hndl; - vertex_hdl_t dest_hndl; - int rc; - int port; - lboard_t *dest_brd; - - /* Don't add duplicate boards. */ - if (brd->brd_flags & DUPLICATE_BOARD) { - return; - } - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - - rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl); - - if (rc != GRAPH_SUCCESS) - return; - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find router: %s", path_buffer); - - /* We don't know what to do with multiple router components */ - if (brd->brd_numcompts != 1) { - printk("klhwg_connect_one_router: %d cmpts on router\n", - brd->brd_numcompts); - return; - } - - - /* Convert component 0 to klrou_t ptr */ - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), - brd->brd_compts[0]); - - for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - /* See if the port's active */ - if (router->rou_port[port].port_nasid == INVALID_NASID) { - GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n", - port)); - continue; - } - if (nasid_to_cnodeid(router->rou_port[port].port_nasid) - == INVALID_CNODEID) { - continue; - } - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - printk("Can't find router: %s", dest_path); - return; - } - - sprintf(dest_path, "%d", port); - - rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path); - - if (rc == GRAPH_DUP) { - GRPRINTF(("Skipping port %d. nasid %d %s/%s\n", - port, router->rou_port[port].port_nasid, - path_buffer, dest_path)); - continue; - } - - if (rc != GRAPH_SUCCESS) { - printk("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - return; - } - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, router_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", dest_path); - - } -} - - -static void __init -klhwg_connect_routers(vertex_hdl_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - - for (cnode = 0; cnode < numnodes; cnode++) { - nasid = cnodeid_to_nasid(cnode); - brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); - - if (!brd) - continue; - - do { - - nasid = cnodeid_to_nasid(cnode); - - klhwg_connect_one_router(hwgraph_root, brd, - cnode, nasid); - - /* Find the rest of the routers stored on this node. */ - } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), KLTYPE_ROUTER)) ); - } -} - - - -static void __init -klhwg_connect_hubs(vertex_hdl_t hwgraph_root) -{ - nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd; - klhub_t *hub; - lboard_t *dest_brd; - vertex_hdl_t hub_hndl; - vertex_hdl_t dest_hndl; - char path_buffer[50]; - char dest_path[50]; - graph_error_t rc; - int port; - - for (cnode = 0; cnode < numionodes; cnode++) { - nasid = cnodeid_to_nasid(cnode); - - brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); - ASSERT(hub); - - for (port = 1; port <= MAX_NI_PORTS; port++) { - if (hub->hub_port[port].port_nasid == INVALID_NASID) { - continue; /* Port not active */ - } - - if (nasid_to_cnodeid(hub->hub_port[port].port_nasid) == INVALID_CNODEID) - continue; - - /* Generate a hardware graph path for this board. */ - board_to_path(brd, path_buffer); - rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl); - - if (rc != GRAPH_SUCCESS) - printk(KERN_WARNING "Can't find hub: %s", path_buffer); - - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - hub->hub_port[port].port_nasid, - hub->hub_port[port].port_offset); - - /* Generate a hardware graph path for this board. */ - board_to_path(dest_brd, dest_path); - - rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl); - - if (rc != GRAPH_SUCCESS) { - if (KL_CONFIG_DUPLICATE_BOARD(dest_brd)) - continue; - printk("Can't find board: %s", dest_path); - return; - } else { - char buf[1024]; - - rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, NULL, "Created link path.\n"); - - sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT); - rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl); - sprintf(buf,"%d",port); - rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", buf); - - if (rc != GRAPH_SUCCESS) { - printk("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n", - path_buffer, dest_path, (void *)dest_hndl, rc); - return; - } - } - } - } -} - -void __init -klhwg_add_all_modules(vertex_hdl_t hwgraph_root) -{ - cmoduleid_t cm; - char name[128]; - vertex_hdl_t vhdl; - vertex_hdl_t module_vhdl; - int rc; - char buffer[16]; - - /* Add devices under each module */ - - for (cm = 0; cm < nummodules; cm++) { - /* Use module as module vertex fastinfo */ - - memset(buffer, 0, 16); - format_module_id(buffer, sn_modules[cm]->id, MODULE_FORMAT_BRIEF); - sprintf(name, EDGE_LBL_MODULE "/%s", buffer); - - rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl); - ASSERT(rc == GRAPH_SUCCESS); - rc = rc; - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n"); - - hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) sn_modules[cm]); - - /* Add system controller */ - sprintf(name, - EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1, - buffer); - - rc = hwgraph_path_add(hwgraph_root, name, &vhdl); - ASSERT_ALWAYS(rc == GRAPH_SUCCESS); - rc = rc; - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, vhdl, NULL, "Created L1 path.\n"); - - hwgraph_info_add_LBL(vhdl, INFO_LBL_ELSC, - (arbitrary_info_t)1); - - } -} - -void __init -klhwg_add_all_nodes(vertex_hdl_t hwgraph_root) -{ - cnodeid_t cnode; - - for (cnode = 0; cnode < numionodes; cnode++) { - klhwg_add_node(hwgraph_root, cnode); - } - - for (cnode = 0; cnode < numionodes; cnode++) { - klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode)); - } - - /* - * As for router hardware inventory information, we set this - * up in router.c. - */ - - klhwg_add_all_routers(hwgraph_root); - klhwg_connect_routers(hwgraph_root); - klhwg_connect_hubs(hwgraph_root); -} diff --git a/arch/ia64/sn/io/sn2/l1_command.c b/arch/ia64/sn/io/sn2/l1_command.c deleted file mode 100644 index 95c9e9760..000000000 --- a/arch/ia64/sn/io/sn2/l1_command.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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. - * - * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* elsc_display_line writes up to 12 characters to either the top or bottom - * line of the L1 display. line points to a buffer containing the message - * to be displayed. The zero-based line number is specified by lnum (so - * lnum == 0 specifies the top line and lnum == 1 specifies the bottom). - * Lines longer than 12 characters, or line numbers not less than - * L1_DISPLAY_LINES, cause elsc_display_line to return an error. - */ -int elsc_display_line(nasid_t nasid, char *line, int lnum) -{ - return 0; -} - - -/* - * iobrick routines - */ - -/* iobrick_rack_bay_type_get fills in the three int * arguments with the - * rack number, bay number and brick type of the L1 being addressed. Note - * that if the L1 operation fails and this function returns an error value, - * garbage may be written to brick_type. - */ - - -int iobrick_rack_bay_type_get( nasid_t nasid, uint *rack, - uint *bay, uint *brick_type ) -{ - int result = 0; - - if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) - return( ELSC_ERROR_CMD_SEND ); - - *rack = (result & MODULE_RACK_MASK) >> MODULE_RACK_SHFT; - *bay = (result & MODULE_BPOS_MASK) >> MODULE_BPOS_SHFT; - *brick_type = (result & MODULE_BTYPE_MASK) >> MODULE_BTYPE_SHFT; - return 0; -} - - -int iomoduleid_get(nasid_t nasid) -{ - int result = 0; - - if ( ia64_sn_sysctl_iobrick_module_get(nasid, &result) ) - return( ELSC_ERROR_CMD_SEND ); - - return result; -} - -int -iobrick_type_get_nasid(nasid_t nasid) -{ - uint rack, bay, type; - int t, ret; - extern char brick_types[]; - - if ((ret = iobrick_rack_bay_type_get(nasid, &rack, &bay, &type)) < 0) { - return ret; - } - - /* convert brick_type to lower case */ - if ((type >= 'A') && (type <= 'Z')) - type = type - 'A' + 'a'; - - /* convert to a module.h brick type */ - for( t = 0; t < MAX_BRICK_TYPES; t++ ) { - if( brick_types[t] == type ) { - return t; - } - } - - return -1; /* unknown brick */ -} - -/* - * given a L1 bricktype, return a bricktype string. This string is the - * string that will be used in the hwpath for I/O bricks - */ -char * -iobrick_L1bricktype_to_name(int type) -{ - switch (type) - { - default: - return("Unknown"); - - case L1_BRICKTYPE_PX: - return(EDGE_LBL_PXBRICK); - - case L1_BRICKTYPE_OPUS: - return(EDGE_LBL_OPUSBRICK); - - case L1_BRICKTYPE_IX: - return(EDGE_LBL_IXBRICK); - - case L1_BRICKTYPE_C: - return("Cbrick"); - - case L1_BRICKTYPE_R: - return("Rbrick"); - - case L1_BRICKTYPE_CHI_CG: - return(EDGE_LBL_CGBRICK); - } -} - diff --git a/arch/ia64/sn/io/sn2/ml_SN_init.c b/arch/ia64/sn/io/sn2/ml_SN_init.c deleted file mode 100644 index 6de1ba85c..000000000 --- a/arch/ia64/sn/io/sn2/ml_SN_init.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int maxcpus; - -extern xwidgetnum_t hub_widget_id(nasid_t); - -/* XXX - Move the meat of this to intr.c ? */ -/* - * Set up the platform-dependent fields in the nodepda. - */ -void init_platform_nodepda(nodepda_t *npda, cnodeid_t node) -{ - hubinfo_t hubinfo; - nasid_t nasid; - - /* Allocate per-node platform-dependent data */ - - nasid = cnodeid_to_nasid(node); - if (node >= numnodes) /* Headless/memless IO nodes */ - hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(0), sizeof(struct hubinfo_s)); - else - hubinfo = (hubinfo_t)alloc_bootmem_node(NODE_DATA(node), sizeof(struct hubinfo_s)); - - npda->pdinfo = (void *)hubinfo; - hubinfo->h_nodepda = npda; - hubinfo->h_cnodeid = node; - - spin_lock_init(&hubinfo->h_crblock); - - npda->xbow_peer = INVALID_NASID; - - /* - * Initialize the linked list of - * router info pointers to the dependent routers - */ - npda->npda_rip_first = NULL; - - /* - * npda_rip_last always points to the place - * where the next element is to be inserted - * into the list - */ - npda->npda_rip_last = &npda->npda_rip_first; - npda->geoid.any.type = GEO_TYPE_INVALID; - - init_MUTEX_LOCKED(&npda->xbow_sema); /* init it locked? */ -} - -void -init_platform_hubinfo(nodepda_t **nodepdaindr) -{ - cnodeid_t cnode; - hubinfo_t hubinfo; - nodepda_t *npda; - extern int numionodes; - - if (IS_RUNNING_ON_SIMULATOR()) - return; - for (cnode = 0; cnode < numionodes; cnode++) { - npda = nodepdaindr[cnode]; - hubinfo = (hubinfo_t)npda->pdinfo; - hubinfo->h_nasid = cnodeid_to_nasid(cnode); - hubinfo->h_widgetid = hub_widget_id(hubinfo->h_nasid); - } -} - -void -update_node_information(cnodeid_t cnodeid) -{ - nodepda_t *npda = NODEPDA(cnodeid); - nodepda_router_info_t *npda_rip; - - /* Go through the list of router info - * structures and copy some frequently - * accessed info from the info hanging - * off the corresponding router vertices - */ - npda_rip = npda->npda_rip_first; - while(npda_rip) { - if (npda_rip->router_infop) { - npda_rip->router_portmask = - npda_rip->router_infop->ri_portmask; - npda_rip->router_slot = - npda_rip->router_infop->ri_slotnum; - } else { - /* No router, no ports. */ - npda_rip->router_portmask = 0; - } - npda_rip = npda_rip->router_next; - } -} diff --git a/arch/ia64/sn/io/sn2/ml_SN_intr.c b/arch/ia64/sn/io/sn2/ml_SN_intr.c deleted file mode 100644 index 1d90a3652..000000000 --- a/arch/ia64/sn/io/sn2/ml_SN_intr.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern irqpda_t *irqpdaindr; -extern cnodeid_t master_node_get(vertex_hdl_t vhdl); -extern nasid_t master_nasid; - -/* Initialize some shub registers for interrupts, both IO and error. */ -void intr_init_vecblk(cnodeid_t node) -{ - int nasid = cnodeid_to_nasid(node); - sh_ii_int0_config_u_t ii_int_config; - cpuid_t cpu; - cpuid_t cpu0, cpu1; - sh_ii_int0_enable_u_t ii_int_enable; - sh_int_node_id_config_u_t node_id_config; - sh_local_int5_config_u_t local5_config; - sh_local_int5_enable_u_t local5_enable; - - if (is_headless_node(node) ) { - struct ia64_sal_retval ret_stuff; - int cnode; - - /* retarget all interrupts on this node to the master node. */ - node_id_config.sh_int_node_id_config_regval = 0; - node_id_config.sh_int_node_id_config_s.node_id = master_nasid; - node_id_config.sh_int_node_id_config_s.id_sel = 1; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_INT_NODE_ID_CONFIG), - node_id_config.sh_int_node_id_config_regval); - cnode = nasid_to_cnodeid(master_nasid); - cpu = first_cpu(node_to_cpumask(cnode)); - cpu = cpu_physical_id(cpu); - SAL_CALL(ret_stuff, SN_SAL_REGISTER_CE, nasid, cpu, master_nasid,0,0,0,0); - if (ret_stuff.status < 0) - printk("%s: SN_SAL_REGISTER_CE SAL_CALL failed\n",__FUNCTION__); - } else { - cpu = first_cpu(node_to_cpumask(node)); - cpu = cpu_physical_id(cpu); - } - - /* Get the physical id's of the cpu's on this node. */ - cpu0 = nasid_slice_to_cpu_physical_id(nasid, 0); - cpu1 = nasid_slice_to_cpu_physical_id(nasid, 2); - - HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_ERROR_MASK), 0); - HUB_S( (unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_PI_CRBP_ERROR_MASK), 0); - - /* Config and enable UART interrupt, all nodes. */ - local5_config.sh_local_int5_config_regval = 0; - local5_config.sh_local_int5_config_s.idx = SGI_UART_VECTOR; - local5_config.sh_local_int5_config_s.pid = cpu; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_CONFIG), - local5_config.sh_local_int5_config_regval); - - local5_enable.sh_local_int5_enable_regval = 0; - local5_enable.sh_local_int5_enable_s.uart_int = 1; - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_LOCAL_INT5_ENABLE), - local5_enable.sh_local_int5_enable_regval); - - - /* The II_INT_CONFIG register for cpu 0. */ - ii_int_config.sh_ii_int0_config_regval = 0; - ii_int_config.sh_ii_int0_config_s.type = 0; - ii_int_config.sh_ii_int0_config_s.agt = 0; - ii_int_config.sh_ii_int0_config_s.pid = cpu0; - ii_int_config.sh_ii_int0_config_s.base = 0; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_CONFIG), - ii_int_config.sh_ii_int0_config_regval); - - - /* The II_INT_CONFIG register for cpu 1. */ - ii_int_config.sh_ii_int0_config_regval = 0; - ii_int_config.sh_ii_int0_config_s.type = 0; - ii_int_config.sh_ii_int0_config_s.agt = 0; - ii_int_config.sh_ii_int0_config_s.pid = cpu1; - ii_int_config.sh_ii_int0_config_s.base = 0; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_CONFIG), - ii_int_config.sh_ii_int0_config_regval); - - - /* Enable interrupts for II_INT0 and 1. */ - ii_int_enable.sh_ii_int0_enable_regval = 0; - ii_int_enable.sh_ii_int0_enable_s.ii_enable = 1; - - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT0_ENABLE), - ii_int_enable.sh_ii_int0_enable_regval); - HUB_S((unsigned long *)GLOBAL_MMR_ADDR(nasid, SH_II_INT1_ENABLE), - ii_int_enable.sh_ii_int0_enable_regval); -} - -static int intr_reserve_level(cpuid_t cpu, int bit) -{ - irqpda_t *irqs = irqpdaindr; - int min_shared; - int i; - - if (bit < 0) { - for (i = IA64_SN2_FIRST_DEVICE_VECTOR; i <= IA64_SN2_LAST_DEVICE_VECTOR; i++) { - if (irqs->irq_flags[i] == 0) { - bit = i; - break; - } - } - } - - if (bit < 0) { /* ran out of irqs. Have to share. This will be rare. */ - min_shared = 256; - for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { - /* Share with the same device class */ - /* XXX: gross layering violation.. */ - if (irqpdaindr->curr->vendor == irqpdaindr->device_dev[i]->vendor && - irqpdaindr->curr->device == irqpdaindr->device_dev[i]->device && - irqpdaindr->share_count[i] < min_shared) { - min_shared = irqpdaindr->share_count[i]; - bit = i; - } - } - - min_shared = 256; - if (bit < 0) { /* didn't find a matching device, just pick one. This will be */ - /* exceptionally rare. */ - for (i=IA64_SN2_FIRST_DEVICE_VECTOR; i < IA64_SN2_LAST_DEVICE_VECTOR; i++) { - if (irqpdaindr->share_count[i] < min_shared) { - min_shared = irqpdaindr->share_count[i]; - bit = i; - } - } - } - irqpdaindr->share_count[bit]++; - } - - if (!(irqs->irq_flags[bit] & SN2_IRQ_SHARED)) { - if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) - return -1; - irqs->num_irq_used++; - } - - irqs->irq_flags[bit] |= SN2_IRQ_RESERVED; - return bit; -} - -void intr_unreserve_level(cpuid_t cpu, - int bit) -{ - irqpda_t *irqs = irqpdaindr; - - if (irqs->irq_flags[bit] & SN2_IRQ_RESERVED) { - irqs->num_irq_used--; - irqs->irq_flags[bit] &= ~SN2_IRQ_RESERVED; - } -} - -int intr_connect_level(cpuid_t cpu, int bit) -{ - irqpda_t *irqs = irqpdaindr; - - if (!(irqs->irq_flags[bit] & SN2_IRQ_SHARED) && - (irqs->irq_flags[bit] & SN2_IRQ_CONNECTED)) - return -1; - - irqs->irq_flags[bit] |= SN2_IRQ_CONNECTED; - return bit; -} - -int intr_disconnect_level(cpuid_t cpu, int bit) -{ - irqpda_t *irqs = irqpdaindr; - - if (!(irqs->irq_flags[bit] & SN2_IRQ_CONNECTED)) - return -1; - irqs->irq_flags[bit] &= ~SN2_IRQ_CONNECTED; - return bit; -} - -/* - * Choose a cpu on this node. - * - * We choose the one with the least number of int's assigned to it. - */ -static cpuid_t intr_cpu_choose_from_node(cnodeid_t cnode) -{ - cpuid_t cpu, best_cpu = CPU_NONE; - int slice, min_count = 1000; - - for (slice = CPUS_PER_NODE - 1; slice >= 0; slice--) { - int intrs; - - cpu = cnode_slice_to_cpuid(cnode, slice); - if (cpu == NR_CPUS) - continue; - if (!cpu_online(cpu)) - continue; - - intrs = pdacpu(cpu)->sn_num_irqs; - - if (min_count > intrs) { - min_count = intrs; - best_cpu = cpu; - if (enable_shub_wars_1_1()) { - /* - * Rather than finding the best cpu, always - * return the first cpu. This forces all - * interrupts to the same cpu - */ - break; - } - } - } - pdacpu(best_cpu)->sn_num_irqs++; - return best_cpu; -} - -/* - * We couldn't put it on the closest node. Try to find another one. - * Do a stupid round-robin assignment of the node. - */ -static cpuid_t intr_cpu_choose_node(void) -{ - static cnodeid_t last_node = -1; /* XXX: racy */ - cnodeid_t candidate_node; - cpuid_t cpuid; - - if (last_node >= numnodes) - last_node = 0; - - for (candidate_node = last_node + 1; candidate_node != last_node; - candidate_node++) { - if (candidate_node == numnodes) - candidate_node = 0; - cpuid = intr_cpu_choose_from_node(candidate_node); - if (cpuid != CPU_NONE) - return cpuid; - } - - return CPU_NONE; -} - -/* - * Find the node to assign for this interrupt. - * - * SN2 + pcibr addressing limitation: - * Due to this limitation, all interrupts from a given bridge must - * go to the name node. The interrupt must also be targetted for - * the same processor. This limitation does not exist on PIC. - * But, the processor limitation will stay. The limitation will be - * similar to the bedrock/xbridge limit regarding PI's - */ -cpuid_t intr_heuristic(vertex_hdl_t dev, int req_bit, int *resp_bit) -{ - cpuid_t cpuid; - vertex_hdl_t pconn_vhdl; - pcibr_soft_t pcibr_soft; - int bit; - - /* XXX: gross layering violation.. */ - if (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) { - pcibr_soft = pcibr_soft_get(pconn_vhdl); - if (pcibr_soft && pcibr_soft->bsi_err_intr) { - /* - * The cpu was chosen already when we assigned - * the error interrupt. - */ - cpuid = ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid; - goto done; - } - } - - /* - * Need to choose one. Try the controlling c-brick first. - */ - cpuid = intr_cpu_choose_from_node(master_node_get(dev)); - if (cpuid == CPU_NONE) - cpuid = intr_cpu_choose_node(); - - done: - if (cpuid != CPU_NONE) { - bit = intr_reserve_level(cpuid, req_bit); - if (bit >= 0) { - *resp_bit = bit; - return cpuid; - } - } - - printk("Cannot target interrupt to target cpu (%ld).\n", cpuid); - return CPU_NONE; -} diff --git a/arch/ia64/sn/io/sn2/ml_iograph.c b/arch/ia64/sn/io/sn2/ml_iograph.c deleted file mode 100644 index 9bb04c904..000000000 --- a/arch/ia64/sn/io/sn2/ml_iograph.c +++ /dev/null @@ -1,770 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define IOGRAPH_DEBUG */ -#ifdef IOGRAPH_DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif /* IOGRAPH_DEBUG */ - -/* At most 2 hubs can be connected to an xswitch */ -#define NUM_XSWITCH_VOLUNTEER 2 - -/* - * Track which hubs have volunteered to manage devices hanging off of - * a Crosstalk Switch (e.g. xbow). This structure is allocated, - * initialized, and hung off the xswitch vertex early on when the - * xswitch vertex is created. - */ -typedef struct xswitch_vol_s { - struct semaphore xswitch_volunteer_mutex; - int xswitch_volunteer_count; - vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER]; -} *xswitch_vol_t; - -void -xswitch_vertex_init(vertex_hdl_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); - if (!xvolinfo) { - printk(KERN_WARNING "xswitch_vertex_init(): Unable to " - "allocate memory\n"); - return; - } - memset(xvolinfo, 0, sizeof(struct xswitch_vol_s)); - init_MUTEX(&xvolinfo->xswitch_volunteer_mutex); - rc = hwgraph_info_add_LBL(xswitch, INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t)xvolinfo); - ASSERT(rc == GRAPH_SUCCESS); rc = rc; -} - - -/* - * When assignment of hubs to widgets is complete, we no longer need the - * xswitch volunteer structure hanging around. Destroy it. - */ -static void -xswitch_volunteer_delete(vertex_hdl_t xswitch) -{ - xswitch_vol_t xvolinfo; - int rc; - - rc = hwgraph_info_remove_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo > 0) - kfree(xvolinfo); -} -/* - * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. - */ -/* ARGSUSED */ -static void -volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master) -{ - xswitch_vol_t xvolinfo = NULL; - vertex_hdl_t hubv; - hubinfo_t hubinfo; - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { - if (!is_headless_node_vertex(master)) { - char name[MAXDEVNAME]; - printk(KERN_WARNING - "volunteer for widgets: vertex %s has no info label", - vertex_to_name(xswitch, name, MAXDEVNAME)); - } - return; - } - - down(&xvolinfo->xswitch_volunteer_mutex); - ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); - xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; - xvolinfo->xswitch_volunteer_count++; - - /* - * if dual ported, make the lowest widgetid always be - * xswitch_volunteer[0]. - */ - if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { - hubv = xvolinfo->xswitch_volunteer[0]; - hubinfo_get(hubv, &hubinfo); - if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { - xvolinfo->xswitch_volunteer[0] = - xvolinfo->xswitch_volunteer[1]; - xvolinfo->xswitch_volunteer[1] = hubv; - } - } - up(&xvolinfo->xswitch_volunteer_mutex); -} - -extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum); - -/* - * Assign all the xwidgets hanging off the specified xswitch to the - * Crosstalk masters that have volunteered for xswitch duty. - */ -/* ARGSUSED */ -static void -assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv) -{ - xswitch_info_t xswitch_info; - xswitch_vol_t xvolinfo = NULL; - xwidgetnum_t widgetnum; - int num_volunteer; - nasid_t nasid; - hubinfo_t hubinfo; - extern int iobrick_type_get_nasid(nasid_t); - - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - xswitch_info = xswitch_info_get(xswitch); - ASSERT(xswitch_info != NULL); - - (void)hwgraph_info_get_LBL(xswitch, - INFO_LBL_XSWITCH_VOL, - (arbitrary_info_t *)&xvolinfo); - if (xvolinfo == NULL) { - if (!is_headless_node_vertex(hubv)) { - char name[MAXDEVNAME]; - printk(KERN_WARNING - "assign_widgets_to_volunteers:vertex %s has " - " no info label", - vertex_to_name(xswitch, name, MAXDEVNAME)); - } - return; - } - - num_volunteer = xvolinfo->xswitch_volunteer_count; - ASSERT(num_volunteer > 0); - - /* Assign master hub for xswitch itself. */ - if (HUB_WIDGET_ID_MIN > 0) { - hubv = xvolinfo->xswitch_volunteer[0]; - xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); - } - - /* - * TBD: Use administrative information to alter assignment of - * widgets to hubs. - */ - for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { - int i; - - if (!xbow_port_io_enabled(nasid, widgetnum)) - continue; - - /* - * If this is the master IO board, assign it to the same - * hub that owned it in the prom. - */ - if (is_master_baseio_nasid_widget(nasid, widgetnum)) { - extern nasid_t snia_get_master_baseio_nasid(void); - for (i=0; ixswitch_volunteer[i]; - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - if (nasid == snia_get_master_baseio_nasid()) - goto do_assignment; - } - printk("Nasid == %d, console nasid == %d", - nasid, snia_get_master_baseio_nasid()); - nasid = 0; - } - - /* - * Assuming that we're dual-hosted and that PCI cards - * are naturally placed left-to-right, alternate PCI - * buses across both Cbricks. For Pbricks, and Ibricks, - * io_brick_map_widget() returns the PCI bus number - * associated with the given brick type and widget number. - * For Xbricks, it returns the XIO slot number. - */ - - i = 0; - if (num_volunteer > 1) { - int bt; - - bt = iobrick_type_get_nasid(nasid); - if (bt >= 0) { - i = io_brick_map_widget(bt, widgetnum) & 1; - } - } - - hubv = xvolinfo->xswitch_volunteer[i]; - -do_assignment: - /* - * At this point, we want to make hubv the master of widgetnum. - */ - xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); - } - - xswitch_volunteer_delete(xswitch); -} - -/* - * Probe to see if this hub's xtalk link is active. If so, - * return the Crosstalk Identification of the widget that we talk to. - * This is called before any of the Crosstalk infrastructure for - * this hub is set up. It's usually called on the node that we're - * probing, but not always. - * - * TBD: Prom code should actually do this work, and pass through - * hwid for our use. - */ -static void -early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) -{ - nasid_t nasid; - hubinfo_t hubinfo; - hubreg_t llp_csr_reg; - widgetreg_t widget_id; - int result = 0; - - hwid->part_num = XWIDGET_PART_NUM_NONE; - hwid->rev_num = XWIDGET_REV_NUM_NONE; - hwid->mfg_num = XWIDGET_MFG_NUM_NONE; - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - - llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); - if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP)) - return; - - /* Read the Cross-Talk Widget Id on the other end */ - result = snia_badaddr_val((volatile void *) - (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID), - 4, (void *) &widget_id); - - if (result == 0) { /* Found something connected */ - hwid->part_num = XWIDGET_PART_NUM(widget_id); - hwid->rev_num = XWIDGET_REV_NUM(widget_id); - hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); - - /* TBD: link reset */ - } else { - - hwid->part_num = XWIDGET_PART_NUM_NONE; - hwid->rev_num = XWIDGET_REV_NUM_NONE; - hwid->mfg_num = XWIDGET_MFG_NUM_NONE; - } -} - -/* - * io_xswitch_widget_init - * - */ - -static void -io_xswitch_widget_init(vertex_hdl_t xswitchv, - vertex_hdl_t hubv, - xwidgetnum_t widgetnum) -{ - xswitch_info_t xswitch_info; - xwidgetnum_t hub_widgetid; - vertex_hdl_t widgetv; - cnodeid_t cnode; - widgetreg_t widget_id; - nasid_t nasid, peer_nasid; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - /*REFERENCED*/ - int rc; - char pathname[128]; - lboard_t *board = NULL; - char buffer[16]; - char bt; - moduleid_t io_module; - slotid_t get_widget_slotnum(int xbow, int widget); - - DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); - - /* - * Verify that xswitchv is indeed an attached xswitch. - */ - xswitch_info = xswitch_info_get(xswitchv); - ASSERT(xswitch_info != NULL); - - hubinfo_get(hubv, &hubinfo); - nasid = hubinfo->h_nasid; - cnode = nasid_to_cnodeid(nasid); - hub_widgetid = hubinfo->h_widgetid; - - /* - * Check that the widget is an io widget and is enabled - * on this nasid or the `peer' nasid. The peer nasid - * is the other hub/bedrock connected to the xbow. - */ - peer_nasid = NODEPDA(cnode)->xbow_peer; - if (peer_nasid == INVALID_NASID) - /* If I don't have a peer, use myself. */ - peer_nasid = nasid; - if (!xbow_port_io_enabled(nasid, widgetnum) && - !xbow_port_io_enabled(peer_nasid, widgetnum)) { - return; - } - - if (xswitch_info_link_ok(xswitch_info, widgetnum)) { - char name[4]; - lboard_t dummy; - - - /* - * If the current hub is not supposed to be the master - * for this widgetnum, then skip this widget. - */ - if (xswitch_info_master_assignment_get(xswitch_info, - widgetnum) != hubv) { - return; - } - - board = find_lboard_class_nasid( (lboard_t *)KL_CONFIG_INFO(nasid), - nasid, KLCLASS_IOBRICK); - if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) { - board = find_lboard_class_nasid( - (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer), - NODEPDA(cnode)->xbow_peer, KLCLASS_IOBRICK); - } - - if (board) { - DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); - } else { - DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); - board = &dummy; - } - - - /* Copy over the nodes' geoid info */ - { - lboard_t *brd; - - brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); - if ( brd != (lboard_t *)0 ) { - board->brd_geoid = brd->brd_geoid; - } - } - - /* - * Make sure we really want to say xbrick, pbrick, - * etc. rather than XIO, graphics, etc. - */ - - memset(buffer, 0, 16); - format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - - sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d", - buffer, - geo_slab(board->brd_geoid), - (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK : - (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK : - (board->brd_type == KLTYPE_CGBRICK) ? EDGE_LBL_CGBRICK : - (board->brd_type == KLTYPE_OPUSBRICK) ? EDGE_LBL_OPUSBRICK : "?brick", - EDGE_LBL_XTALK, widgetnum); - - DBG("io_xswitch_widget_init: path= %s\n", pathname); - rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); - - ASSERT(rc == GRAPH_SUCCESS); - - /* This is needed to let the user programs to map the - * module,slot numbers to the corresponding widget numbers - * on the crossbow. - */ - device_master_set(hwgraph_connectpt_get(widgetv), hubv); - sprintf(name, "%d", widgetnum); - DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); - rc = hwgraph_edge_add(xswitchv, widgetv, name); - - /* - * crosstalk switch code tracks which - * widget is attached to each link. - */ - xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); - - /* - * Peek at the widget to get its crosstalk part and - * mfgr numbers, then present it to the generic xtalk - * bus provider to have its driver attach routine - * called (or not). - */ - widget_id = XWIDGET_ID_READ(nasid, widgetnum); - hwid.part_num = XWIDGET_PART_NUM(widget_id); - hwid.rev_num = XWIDGET_REV_NUM(widget_id); - hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); - - (void)xwidget_register(&hwid, widgetv, widgetnum, - hubv, hub_widgetid); - - io_module = iomoduleid_get(nasid); - if (io_module >= 0) { - char buffer[16]; - vertex_hdl_t to, from; - char *brick_name; - extern char *iobrick_L1bricktype_to_name(int type); - - - memset(buffer, 0, 16); - format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); - - if ( isupper(MODULE_GET_BTCHAR(io_module)) ) { - bt = tolower(MODULE_GET_BTCHAR(io_module)); - } - else { - bt = MODULE_GET_BTCHAR(io_module); - } - - brick_name = iobrick_L1bricktype_to_name(bt); - - /* Add a helper vertex so xbow monitoring - * can identify the brick type. It's simply - * an edge from the widget 0 vertex to the - * brick vertex. - */ - - sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" - EDGE_LBL_SLAB "/%d/" - EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/" - "0", - buffer, geo_slab(board->brd_geoid)); - from = hwgraph_path_to_vertex(pathname); - ASSERT_ALWAYS(from); - sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" - EDGE_LBL_SLAB "/%d/" - "%s", - buffer, geo_slab(board->brd_geoid), brick_name); - - to = hwgraph_path_to_vertex(pathname); - ASSERT_ALWAYS(to); - rc = hwgraph_edge_add(from, to, - EDGE_LBL_INTERCONNECT); - if (rc != -EEXIST && rc != GRAPH_SUCCESS) { - printk("%s: Unable to establish link" - " for xbmon.", pathname); - } - } - - } -} - - -static void -io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode) -{ - xwidgetnum_t widgetnum; - - DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode); - - for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; - widgetnum++) { - io_xswitch_widget_init(xswitchv, - cnodeid_to_vertex(cnode), - widgetnum); - } -} - -/* - * Initialize all I/O on the specified node. - */ -static void -io_init_node(cnodeid_t cnodeid) -{ - /*REFERENCED*/ - vertex_hdl_t hubv, switchv, widgetv; - struct xwidget_hwid_s hwid; - hubinfo_t hubinfo; - int is_xswitch; - nodepda_t *npdap; - struct semaphore *peer_sema = 0; - uint32_t widget_partnum; - - npdap = NODEPDA(cnodeid); - - /* - * Get the "top" vertex for this node's hardware - * graph; it will carry the per-hub hub-specific - * data, and act as the crosstalk provider master. - * It's canonical path is probably something of the - * form /hw/module/%M/slot/%d/node - */ - hubv = cnodeid_to_vertex(cnodeid); - DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); - - ASSERT(hubv != GRAPH_VERTEX_NONE); - - /* - * attach our hub_provider information to hubv, - * so we can use it as a crosstalk provider "master" - * vertex. - */ - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); - - /* - * If nothing connected to this hub's xtalk port, we're done. - */ - early_probe_for_widget(hubv, &hwid); - if (hwid.part_num == XWIDGET_PART_NUM_NONE) { - DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); - return; - /* NOTREACHED */ - } - - /* - * Create a vertex to represent the crosstalk bus - * attached to this hub, and a vertex to be used - * as the connect point for whatever is out there - * on the other side of our crosstalk connection. - * - * Crosstalk Switch drivers "climb up" from their - * connection point to try and take over the switch - * point. - * - * Of course, the edges and verticies may already - * exist, in which case our net effect is just to - * associate the "xtalk_" driver with the connection - * point for the device. - */ - - (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); - - DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); - - ASSERT(switchv != GRAPH_VERTEX_NONE); - - (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); - - DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); - - /* - * We need to find the widget id and update the basew_id field - * accordingly. In particular, SN00 has direct connected bridge, - * and hence widget id is Not 0. - */ - widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE - (cnodeid_to_nasid(cnodeid), 0) + - WIDGET_ID))) & WIDGET_PART_NUM) - >> WIDGET_PART_NUM_SHFT; - - if ((widget_partnum == XBOW_WIDGET_PART_NUM) || - (widget_partnum == XXBOW_WIDGET_PART_NUM) || - (widget_partnum == PXBOW_WIDGET_PART_NUM) ) { - /* - * Xbow control register does not have the widget ID field. - * So, hard code the widget ID to be zero. - */ - DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); - npdap->basew_id = 0; - - } else { - void *bridge; - - bridge = (void *)NODE_SWIN_BASE(cnodeid_to_nasid(cnodeid), 0); - npdap->basew_id = pcireg_bridge_control_get(bridge) & WIDGET_WIDGET_ID; - - printk(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv); - return; - } - { - char widname[10]; - sprintf(widname, "%x", npdap->basew_id); - (void)hwgraph_path_add(switchv, widname, &widgetv); - DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); - ASSERT(widgetv != GRAPH_VERTEX_NONE); - } - - nodepda->basew_xc = widgetv; - - is_xswitch = xwidget_hwid_is_xswitch(&hwid); - - /* - * Try to become the master of the widget. If this is an xswitch - * with multiple hubs connected, only one will succeed. Mastership - * of an xswitch is used only when touching registers on that xswitch. - * The slave xwidgets connected to the xswitch can be owned by various - * masters. - */ - if (device_master_set(widgetv, hubv) == 0) { - - /* Only one hub (thread) per Crosstalk device or switch makes - * it to here. - */ - - /* - * Initialize whatever xwidget is hanging off our hub. - * Whatever it is, it's accessible through widgetnum 0. - */ - hubinfo_get(hubv, &hubinfo); - - (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid); - - /* - * Special handling for Crosstalk Switches (e.g. xbow). - * We need to do things in roughly the following order: - * 1) Initialize xswitch hardware (done above) - * 2) Determine which hubs are available to be widget masters - * 3) Discover which links are active from the xswitch - * 4) Assign xwidgets hanging off the xswitch to hubs - * 5) Initialize all xwidgets on the xswitch - */ - - volunteer_for_widgets(switchv, hubv); - - /* If there's someone else on this crossbow, recognize him */ - if (npdap->xbow_peer != INVALID_NASID) { - nodepda_t *peer_npdap = NODEPDA(nasid_to_cnodeid(npdap->xbow_peer)); - peer_sema = &peer_npdap->xbow_sema; - volunteer_for_widgets(switchv, peer_npdap->node_vertex); - } - - assign_widgets_to_volunteers(switchv, hubv); - - /* Signal that we're done */ - if (peer_sema) { - up(peer_sema); - } - - } - else { - /* Wait 'til master is done assigning widgets. */ - down(&npdap->xbow_sema); - } - - /* Now both nodes can safely inititialize widgets */ - io_init_xswitch_widgets(switchv, cnodeid); - - DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); -} - -#include - -/* - * Initialize all I/O devices. Starting closest to nodes, probe and - * initialize outward. - */ -void -init_all_devices(void) -{ - cnodeid_t cnodeid, active; - - active = 0; - for (cnodeid = 0; cnodeid < numionodes; cnodeid++) { - DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid); - io_init_node(cnodeid); - - DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid); - } - - for (cnodeid = 0; cnodeid < numnodes; cnodeid++) { - /* - * Update information generated by IO init. - */ - update_node_information(cnodeid); - } -} - -static -struct io_brick_map_s io_brick_tab[] = { - -/* PXbrick widget number to PCI bus number map */ - { MODULE_PXBRICK, /* PXbrick type */ - /* PCI Bus # Widget # */ - { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 0, /* 0x8 */ - 0, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 1, /* 0xc */ - 5, /* 0xd */ - 0, /* 0xe */ - 3 /* 0xf */ - } - }, - -/* OPUSbrick widget number to PCI bus number map */ - { MODULE_OPUSBRICK, /* OPUSbrick type */ - /* PCI Bus # Widget # */ - { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 0, /* 0x8 */ - 0, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 0, /* 0xc */ - 0, /* 0xd */ - 0, /* 0xe */ - 1 /* 0xf */ - } - }, - -/* IXbrick widget number to PCI bus number map */ - { MODULE_IXBRICK, /* IXbrick type */ - /* PCI Bus # Widget # */ - { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 0, /* 0x8 */ - 0, /* 0x9 */ - 0, 0, /* 0xa - 0xb */ - 1, /* 0xc */ - 5, /* 0xd */ - 0, /* 0xe */ - 3 /* 0xf */ - } - }, - -/* CG brick widget number to PCI bus number map */ - { MODULE_CGBRICK, /* CG brick */ - /* PCI Bus # Widget # */ - { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */ - 0, /* 0x8 */ - 0, /* 0x9 */ - 0, 1, /* 0xa - 0xb */ - 0, /* 0xc */ - 0, /* 0xd */ - 0, /* 0xe */ - 0 /* 0xf */ - } - }, -}; - -/* - * Use the brick's type to map a widget number to a meaningful int - */ -int -io_brick_map_widget(int brick_type, int widget_num) -{ - int num_bricks, i; - - /* Calculate number of bricks in table */ - num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]); - - /* Look for brick prefix in table */ - for (i = 0; i < num_bricks; i++) { - if (brick_type == io_brick_tab[i].ibm_type) - return io_brick_tab[i].ibm_map_wid[widget_num]; - } - - return 0; - -} diff --git a/arch/ia64/sn/io/sn2/module.c b/arch/ia64/sn/io/sn2/module.c deleted file mode 100644 index 56e318875..000000000 --- a/arch/ia64/sn/io/sn2/module.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* #define LDEBUG 1 */ - -#ifdef LDEBUG -#define DPRINTF printk -#define printf printk -#else -#define DPRINTF(x...) -#endif - -module_t *sn_modules[MODULE_MAX]; -int nummodules; - -#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 -#define SN0_SERIAL_FUDGE 0x6e - - -static void __init -encode_str_serial(const char *src, char *dest) -{ - int i; - - for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { - - dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + - ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + - SN0_SERIAL_FUDGE; - } -} - -module_t * __init -module_lookup(moduleid_t id) -{ - int i; - - for (i = 0; i < nummodules; i++) - if (sn_modules[i]->id == id) { - DPRINTF("module_lookup: found m=0x%p\n", sn_modules[i]); - return sn_modules[i]; - } - - return NULL; -} - -/* - * module_add_node - * - * The first time a new module number is seen, a module structure is - * inserted into the module list in order sorted by module number - * and the structure is initialized. - * - * The node number is added to the list of nodes in the module. - */ -static module_t * __init -module_add_node(geoid_t geoid, cnodeid_t cnodeid) -{ - module_t *m; - int i; - char buffer[16]; - moduleid_t moduleid; - slabid_t slab_number; - - memset(buffer, 0, 16); - moduleid = geo_module(geoid); - format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF); - DPRINTF("module_add_node: moduleid=%s node=%d\n", buffer, cnodeid); - - if ((m = module_lookup(moduleid)) == 0) { - m = kmalloc(sizeof (module_t), GFP_KERNEL); - ASSERT_ALWAYS(m); - memset(m, 0 , sizeof(module_t)); - - for (slab_number = 0; slab_number <= MAX_SLABS; slab_number++) { - m->nodes[slab_number] = -1; - } - - m->id = moduleid; - spin_lock_init(&m->lock); - - /* Insert in sorted order by module number */ - - for (i = nummodules; i > 0 && sn_modules[i - 1]->id > moduleid; i--) - sn_modules[i] = sn_modules[i - 1]; - - sn_modules[i] = m; - nummodules++; - } - - /* - * Save this information in the correct slab number of the node in the - * module. - */ - slab_number = geo_slab(geoid); - DPRINTF("slab number added 0x%x\n", slab_number); - - if (m->nodes[slab_number] != -1) { - printk("module_add_node .. slab previously found\n"); - return NULL; - } - - m->nodes[slab_number] = cnodeid; - m->geoid[slab_number] = geoid; - - return m; -} - -static int __init -module_probe_snum(module_t *m, nasid_t host_nasid, nasid_t nasid) -{ - lboard_t *board; - klmod_serial_num_t *comp; - char serial_number[16]; - - /* - * record brick serial number - */ - board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(host_nasid), host_nasid, KLTYPE_SNIA); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - { - return 0; - } - - board_serial_number_get( board, serial_number ); - if( serial_number[0] != '\0' ) { - encode_str_serial( serial_number, m->snum.snum_str ); - m->snum_valid = 1; - } - - board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), - nasid, KLTYPE_IOBRICK_XBOW); - - if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) - return 0; - - comp = GET_SNUM_COMP(board); - - if (comp) { - if (comp->snum.snum_str[0] != '\0') { - memcpy(m->sys_snum, comp->snum.snum_str, - MAX_SERIAL_NUM_SIZE); - m->sys_snum_valid = 1; - } - } - - if (m->sys_snum_valid) - return 1; - else { - DPRINTF("Invalid serial number for module %d, " - "possible missing or invalid NIC.", m->id); - return 0; - } -} - -void __init -io_module_init(void) -{ - cnodeid_t node; - lboard_t *board; - nasid_t nasid; - int nserial; - module_t *m; - extern int numionodes; - - DPRINTF("*******module_init\n"); - - nserial = 0; - - /* - * First pass just scan for compute node boards KLTYPE_SNIA. - * We do not support memoryless compute nodes. - */ - for (node = 0; node < numnodes; node++) { - nasid = cnodeid_to_nasid(node); - board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), nasid, KLTYPE_SNIA); - ASSERT(board); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found Shub lboard 0x%lx nasid 0x%x cnode 0x%x \n", (unsigned long)board, (int)nasid, (int)node); - - m = module_add_node(board->brd_geoid, node); - if (! m->snum_valid && module_probe_snum(m, nasid, nasid)) - nserial++; - } - - /* - * Second scan, look for headless/memless board hosted by compute nodes. - */ - for (node = numnodes; node < numionodes; node++) { - nasid_t nasid; - char serial_number[16]; - - nasid = cnodeid_to_nasid(node); - board = find_lboard_nasid((lboard_t *) KL_CONFIG_INFO(nasid), - nasid, KLTYPE_SNIA); - ASSERT(board); - - HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found headless/memless lboard 0x%lx node %d nasid %d cnode %d\n", (unsigned long)board, node, (int)nasid, (int)node); - - m = module_add_node(board->brd_geoid, node); - - /* - * Get and initialize the serial number. - */ - board_serial_number_get( board, serial_number ); - if( serial_number[0] != '\0' ) { - encode_str_serial( serial_number, m->snum.snum_str ); - m->snum_valid = 1; - nserial++; - } - } -} diff --git a/arch/ia64/sn/io/sn2/pcibr/Makefile b/arch/ia64/sn/io/sn2/pcibr/Makefile deleted file mode 100644 index b18606f3f..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# arch/ia64/sn/io/sn2/pcibr/Makefile -# -# 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. -# -# Copyright (C) 2002-2003 Silicon Graphics, Inc. All Rights Reserved. -# -# Makefile for the sn2 specific pci bridge routines. -# - -obj-y += pcibr_ate.o pcibr_config.o \ - pcibr_dvr.o pcibr_hints.o \ - pcibr_intr.o pcibr_rrb.o \ - pcibr_slot.o pcibr_error.o \ - pcibr_reg.o diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c deleted file mode 100644 index bb35b4424..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_ate.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -/* - * functions - */ -int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *); -void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *); -bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned); -bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -void ate_write(pcibr_soft_t, int, int, bridge_ate_t); - -int pcibr_invalidate_ate; /* by default don't invalidate ATE on free */ - -/* - * Allocate "count" contiguous Bridge Address Translation Entries - * on the specified bridge to be used for PCI to XTALK mappings. - * Indices in rm map range from 1..num_entries. Indicies returned - * to caller range from 0..num_entries-1. - * - * Return the start index on success, -1 on failure. - */ -int -pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count, struct resource *res) -{ - int status = 0; - unsigned long flag; - - memset(res, 0, sizeof(struct resource)); - flag = pcibr_lock(pcibr_soft); - status = allocate_resource( &pcibr_soft->bs_int_ate_resource, res, - count, pcibr_soft->bs_int_ate_resource.start, - pcibr_soft->bs_int_ate_resource.end, 1, - NULL, NULL); - if (status) { - /* Failed to allocate */ - pcibr_unlock(pcibr_soft, flag); - return -1; - } - - /* Save the resource for freeing */ - pcibr_unlock(pcibr_soft, flag); - - return res->start; -} - -void -pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count, struct resource *res) -{ - - bridge_ate_t ate; - int status = 0; - unsigned long flags; - - if (pcibr_invalidate_ate) { - /* For debugging purposes, clear the valid bit in the ATE */ - ate = *pcibr_ate_addr(pcibr_soft, index); - ate_write(pcibr_soft, index, count, (ate & ~ATE_V)); - } - - flags = pcibr_lock(pcibr_soft); - status = release_resource(res); - pcibr_unlock(pcibr_soft, flags); - if (status) - BUG(); /* Ouch .. */ - -} - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Address Translation Entry attribute bits. - */ -bridge_ate_t -pcibr_flags_to_ate(pcibr_soft_t pcibr_soft, unsigned flags) -{ - bridge_ate_t attributes; - - /* default if nothing specified: - * NOBARRIER - * NOPREFETCH - * NOPRECISE - * COHERENT - * Plus the valid bit - */ - attributes = ATE_CO | ATE_V; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~ATE_BAR; /* no barrier */ - attributes |= ATE_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= ATE_BAR; /* barrier bit on */ - attributes &= ~ATE_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~ATE_PREF; - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= ATE_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~ATE_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= ATE_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~ATE_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= ATE_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~ATE_PREC; - - /* In PCI-X mode, Prefetch & Precise not supported */ - if (IS_PCIX(pcibr_soft)) { - attributes &= ~(ATE_PREC | ATE_PREF); - } - - return (attributes); -} - -/* - * Setup an Address Translation Entry as specified. Use either the Bridge - * internal maps or the external map RAM, as appropriate. - */ -bridge_ate_p -pcibr_ate_addr(pcibr_soft_t pcibr_soft, - int ate_index) -{ - if (ate_index < pcibr_soft->bs_int_ate_size) { - return (pcireg_int_ate_addr(pcibr_soft, ate_index)); - } else { - printk("pcibr_ate_addr(): INVALID ate_index 0x%x", ate_index); - return (bridge_ate_p)0; - } -} - -/* - * Write the ATE. - */ -void -ate_write(pcibr_soft_t pcibr_soft, int ate_index, int count, bridge_ate_t ate) -{ - while (count-- > 0) { - if (ate_index < pcibr_soft->bs_int_ate_size) { - pcireg_int_ate_set(pcibr_soft, ate_index, ate); - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_soft->bs_vhdl, - "ate_write(): ate_index=0x%x, ate=0x%lx\n", - ate_index, (uint64_t)ate)); - } else { - printk("ate_write(): INVALID ate_index 0x%x", ate_index); - return; - } - ate_index++; - ate += IOPGSIZE; - } - - pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c deleted file mode 100644 index aa489d6a1..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_config.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -extern pcibr_info_t pcibr_info_get(vertex_hdl_t); - -uint64_t pcibr_config_get(vertex_hdl_t, unsigned, unsigned); -uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); -void pcibr_config_set(vertex_hdl_t, unsigned, unsigned, uint64_t); -void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); - -/* - * fancy snia bit twiddling.... - */ -#define CBP(b,r) (((volatile uint8_t *) b)[(r)]) -#define CSP(b,r) (((volatile uint16_t *) b)[((r)/2)]) -#define CWP(b,r) (((volatile uint32_t *) b)[(r)/4]) - -/* - * Return a config space address for given slot / func / offset. Note the - * returned pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to - * the 32bit word that contains the "offset" byte. - */ -cfg_p -pcibr_func_config_addr(pcibr_soft_t soft, pciio_bus_t bus, pciio_slot_t slot, - pciio_function_t func, int offset) -{ - /* - * Type 1 config space - */ - if (bus > 0) { - pcireg_type1_cntr_set(soft, ((bus << 16) | (slot << 11))); - return (pcireg_type1_cfg_addr(soft, func, offset)); - } - - /* - * Type 0 config space - */ - return (pcireg_type0_cfg_addr(soft, slot, func, offset)); -} - -/* - * Return config space address for given slot / offset. Note the returned - * pointer is a 32bit word (ie. cfg_p) aligned pointer pointing to the - * 32bit word that contains the "offset" byte. - */ -cfg_p -pcibr_slot_config_addr(pcibr_soft_t soft, pciio_slot_t slot, int offset) -{ - return pcibr_func_config_addr(soft, 0, slot, 0, offset); -} - -/* - * Set config space data for given slot / func / offset - */ -void -pcibr_func_config_set(pcibr_soft_t soft, pciio_slot_t slot, - pciio_function_t func, int offset, unsigned val) -{ - cfg_p cfg_base; - - cfg_base = pcibr_func_config_addr(soft, 0, slot, func, 0); - do_pcibr_config_set(cfg_base, offset, sizeof(unsigned), val); -} - -int pcibr_config_debug = 0; - -cfg_p -pcibr_config_addr(vertex_hdl_t conn, - unsigned reg) -{ - pcibr_info_t pcibr_info; - pciio_bus_t pciio_bus; - pciio_slot_t pciio_slot; - pciio_function_t pciio_func; - cfg_p cfgbase = (cfg_p)0; - pciio_info_t pciio_info; - - pciio_info = pciio_info_get(conn); - pcibr_info = pcibr_info_get(conn); - - /* - * Determine the PCI bus/slot/func to generate a config address for. - */ - - if (pciio_info_type1_get(pciio_info)) { - /* - * Conn is a vhdl which uses TYPE 1 addressing explicitly passed - * in reg. - */ - pciio_bus = PCI_TYPE1_BUS(reg); - pciio_slot = PCI_TYPE1_SLOT(reg); - pciio_func = PCI_TYPE1_FUNC(reg); - - ASSERT(pciio_bus != 0); - } else { - /* - * Conn is directly connected to the host bus. PCI bus number is - * hardcoded to 0 (even though it may have a logical bus number != 0) - * and slot/function are derived from the pcibr_info_t associated - * with the device. - */ - pciio_bus = 0; - - pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); - if (pciio_slot == PCIIO_SLOT_NONE) - pciio_slot = PCI_TYPE1_SLOT(reg); - - pciio_func = pcibr_info->f_func; - if (pciio_func == PCIIO_FUNC_NONE) - pciio_func = PCI_TYPE1_FUNC(reg); - } - - cfgbase = pcibr_func_config_addr((pcibr_soft_t) pcibr_info->f_mfast, - pciio_bus, pciio_slot, pciio_func, 0); - - return cfgbase; -} - -uint64_t -pcibr_config_get(vertex_hdl_t conn, - unsigned reg, - unsigned size) -{ - return do_pcibr_config_get(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size); -} - -uint64_t -do_pcibr_config_get(cfg_p cfgbase, - unsigned reg, - unsigned size) -{ - unsigned value; - - value = CWP(cfgbase, reg); - if (reg & 3) - value >>= 8 * (reg & 3); - if (size < 4) - value &= (1 << (8 * size)) - 1; - return value; -} - -void -pcibr_config_set(vertex_hdl_t conn, - unsigned reg, - unsigned size, - uint64_t value) -{ - do_pcibr_config_set(pcibr_config_addr(conn, reg), - PCI_TYPE1_REG(reg), size, value); -} - -void -do_pcibr_config_set(cfg_p cfgbase, - unsigned reg, - unsigned size, - uint64_t value) -{ - switch (size) { - case 1: - CBP(cfgbase, reg) = value; - break; - case 2: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CBP(cfgbase, reg + 1) = value >> 8; - } else - CSP(cfgbase, reg) = value; - break; - case 3: - if (reg & 1) { - CBP(cfgbase, reg) = value; - CSP(cfgbase, (reg + 1)) = value >> 8; - } else { - CSP(cfgbase, reg) = value; - CBP(cfgbase, reg + 2) = value >> 16; - } - break; - case 4: - CWP(cfgbase, reg) = value; - break; - } -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c deleted file mode 100644 index b632a685a..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c +++ /dev/null @@ -1,2662 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * global variables to toggle the different levels of pcibr debugging. - * -pcibr_debug_mask is the mask of the different types of debugging - * you want to enable. See sys/PCI/pcibr_private.h - * -pcibr_debug_module is the module you want to trace. By default - * all modules are trace. The format is something like "001c10". - * -pcibr_debug_widget is the widget you want to trace. For TIO - * based bricks use the corelet id. - * -pcibr_debug_slot is the pci slot you want to trace. - */ -uint32_t pcibr_debug_mask; /* 0x00000000 to disable */ -static char *pcibr_debug_module = "all"; /* 'all' for all modules */ -static int pcibr_debug_widget = -1; /* '-1' for all widgets */ -static int pcibr_debug_slot = -1; /* '-1' for all slots */ - - -#if PCIBR_SOFT_LIST -pcibr_list_p pcibr_list; -#endif - -extern char *pci_space[]; - -/* ===================================================================== - * Function Table of Contents - * - * The order of functions in this file has stopped - * making much sense. We might want to take a look - * at it some time and bring back some sanity, or - * perhaps bust this file into smaller chunks. - */ - -extern void do_pcibr_rrb_free_all(pcibr_soft_t, pciio_slot_t); -extern void do_pcibr_rrb_autoalloc(pcibr_soft_t, int, int, int); -extern void pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, int slot, - int vchan, int more_rrbs); - -extern int pcibr_wrb_flush(vertex_hdl_t); -extern int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); -void pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int); - -extern void pcibr_rrb_flush(vertex_hdl_t); - -static int pcibr_try_set_device(pcibr_soft_t, pciio_slot_t, unsigned, uint64_t); -void pcibr_release_device(pcibr_soft_t, pciio_slot_t, uint64_t); - -extern iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, - pciio_space_t, int, int, int); -extern int hwgraph_vertex_name_get(vertex_hdl_t vhdl, char *buf, - uint buflen); - -int pcibr_detach(vertex_hdl_t); -void pcibr_directmap_init(pcibr_soft_t); -int pcibr_pcix_rbars_calc(pcibr_soft_t); -extern int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *); -extern void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *); -extern pciio_dmamap_t get_free_pciio_dmamap(vertex_hdl_t); -extern void free_pciio_dmamap(pcibr_dmamap_t); -extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); - -extern void ate_write(pcibr_soft_t, int, int, bridge_ate_t); - -pcibr_info_t pcibr_info_get(vertex_hdl_t); - -static iopaddr_t pcibr_addr_pci_to_xio(vertex_hdl_t, pciio_slot_t, pciio_space_t, iopaddr_t, size_t, unsigned); - -pcibr_piomap_t pcibr_piomap_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, size_t, unsigned); -void pcibr_piomap_free(pcibr_piomap_t); -caddr_t pcibr_piomap_addr(pcibr_piomap_t, iopaddr_t, size_t); -void pcibr_piomap_done(pcibr_piomap_t); -caddr_t pcibr_piotrans_addr(vertex_hdl_t, device_desc_t, pciio_space_t, iopaddr_t, size_t, unsigned); -iopaddr_t pcibr_piospace_alloc(vertex_hdl_t, device_desc_t, pciio_space_t, size_t, size_t); -void pcibr_piospace_free(vertex_hdl_t, pciio_space_t, iopaddr_t, size_t); - -static iopaddr_t pcibr_flags_to_d64(unsigned, pcibr_soft_t); -extern bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned); - -pcibr_dmamap_t pcibr_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); -void pcibr_dmamap_free(pcibr_dmamap_t); -extern bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); -static iopaddr_t pcibr_addr_xio_to_pci(pcibr_soft_t, iopaddr_t, size_t); -iopaddr_t pcibr_dmamap_addr(pcibr_dmamap_t, paddr_t, size_t); -void pcibr_dmamap_done(pcibr_dmamap_t); -cnodeid_t pcibr_get_dmatrans_node(vertex_hdl_t); -iopaddr_t pcibr_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); -void pcibr_dmamap_drain(pcibr_dmamap_t); -void pcibr_dmaaddr_drain(vertex_hdl_t, paddr_t, size_t); -iopaddr_t pcibr_dmamap_pciaddr_get(pcibr_dmamap_t); - -void pcibr_provider_startup(vertex_hdl_t); -void pcibr_provider_shutdown(vertex_hdl_t); - -int pcibr_reset(vertex_hdl_t); -pciio_endian_t pcibr_endian_set(vertex_hdl_t, pciio_endian_t, pciio_endian_t); -int pcibr_device_flags_set(vertex_hdl_t, pcibr_device_flags_t); - -extern int pcibr_slot_info_free(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_detach(vertex_hdl_t, pciio_slot_t, int, - char *, int *); - -pciio_businfo_t pcibr_businfo_get(vertex_hdl_t); - -/* ===================================================================== - * Device(x) register management - */ - -/* pcibr_try_set_device: attempt to modify Device(x) - * for the specified slot on the specified bridge - * as requested in flags, limited to the specified - * bits. Returns which BRIDGE bits were in conflict, - * or ZERO if everything went OK. - * - * Caller MUST hold pcibr_lock when calling this function. - */ -static int -pcibr_try_set_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - unsigned flags, - uint64_t mask) -{ - pcibr_soft_slot_t slotp; - uint64_t old; - uint64_t new; - uint64_t chg; - uint64_t bad; - uint64_t badpmu; - uint64_t badd32; - uint64_t badd64; - uint64_t fix; - unsigned long s; - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - old = slotp->bss_device; - - /* figure out what the desired - * Device(x) bits are based on - * the flags specified. - */ - - new = old; - - /* Currently, we inherit anything that - * the new caller has not specified in - * one way or another, unless we take - * action here to not inherit. - * - * This is needed for the "swap" stuff, - * since it could have been set via - * pcibr_endian_set -- altho note that - * any explicit PCIBR_BYTE_STREAM or - * PCIBR_WORD_VALUES will freely override - * the effect of that call (and vice - * versa, no protection either way). - * - * I want to get rid of pcibr_endian_set - * in favor of tracking DMA endianness - * using the flags specified when DMA - * channels are created. - */ - -#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN) -#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) - - /* Do not use Barrier, Write Gather, - * or Prefetch unless asked. - * Leave everything else as it - * was from the last time. - */ - new = new - & ~BRIDGE_DEV_BARRIER - & ~BRIDGE_DEV_WRGA_BITS - & ~BRIDGE_DEV_PREF - ; - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { - new = (new - & ~BRIDGE_DEV_BARRIER) /* barrier off */ - | BRIDGE_DEV_PREF; /* prefetch on */ - - } - if (flags & PCIIO_DMA_CMD) { - new = ((new - & ~BRIDGE_DEV_PREF) /* prefetch off */ - & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ - | BRIDGE_DEV_BARRIER; /* barrier on */ - } - /* Generic detail flags - */ - if (flags & PCIIO_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIIO_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIIO_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_WRITE_GATHER) - new |= BRIDGE_DEV_WRGA_BITS; - if (flags & PCIBR_NOWRITE_GATHER) - new &= ~BRIDGE_DEV_WRGA_BITS; - - if (flags & PCIIO_BYTE_STREAM) - new |= BRIDGE_DEV_SWAP_DIR; - if (flags & PCIIO_WORD_VALUES) - new &= ~BRIDGE_DEV_SWAP_DIR; - - /* Provider-specific flags - */ - if (flags & PCIBR_PREFETCH) - new |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - new &= ~BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - new |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - new &= ~BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - new |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - new &= ~BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - new |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - new &= ~BRIDGE_DEV_DEV_SIZE; - - /* - * PIC BRINGUP WAR (PV# 855271): - * Allow setting BRIDGE_DEV_VIRTUAL_EN on PIC iff we're a 64-bit - * device. The bit is only intended for 64-bit devices and, on - * PIC, can cause problems for 32-bit devices. - */ - if (mask == BRIDGE_DEV_D64_BITS && - PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { - if (flags & PCIBR_VCHAN1) { - new |= BRIDGE_DEV_VIRTUAL_EN; - mask |= BRIDGE_DEV_VIRTUAL_EN; - } - } - - /* PIC BRINGUP WAR (PV# 878674): Don't allow 64bit PIO accesses */ - if ((flags & PCIBR_64BIT) && - PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) { - new &= ~(1ull << 22); - } - - chg = old ^ new; /* what are we changing, */ - chg &= mask; /* of the interesting bits */ - - if (chg) { - - badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; - badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; - badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; - bad = badpmu | badd32 | badd64; - - if (bad) { - - /* some conflicts can be resolved by - * forcing the bit on. this may cause - * some performance degredation in - * the stream(s) that want the bit off, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_PRECISE | - BRIDGE_DEV_BARRIER)) ) { - bad &= ~fix; - /* don't change these bits if - * they are already set in "old" - */ - chg &= ~(fix & old); - } - /* some conflicts can be resolved by - * forcing the bit off. this may cause - * some performance degredation in - * the stream(s) that want the bit on, - * but the alternative is not allowing - * the new stream at all. - */ - if ( (fix = bad & (BRIDGE_DEV_WRGA_BITS | - BRIDGE_DEV_PREF)) ) { - bad &= ~fix; - /* don't change these bits if - * we wanted to turn them on. - */ - chg &= ~(fix & new); - } - /* conflicts in other bits mean - * we can not establish this DMA - * channel while the other(s) are - * still present. - */ - if (bad) { - pcibr_unlock(pcibr_soft, s); - PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, - "pcibr_try_set_device: mod blocked by 0x%x\n", bad)); - return bad; - } - } - } - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr++; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr++; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr++; - - /* the value we want to write is the - * original value, with the bits for - * our selected changes flipped, and - * with any disabled features turned off. - */ - new = old ^ chg; /* only change what we want to change */ - - if (slotp->bss_device == new) { - pcibr_unlock(pcibr_soft, s); - return 0; - } - - pcireg_device_set(pcibr_soft, slot, new); - slotp->bss_device = new; - pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pcibr_soft->bs_vhdl, - "pcibr_try_set_device: Device(%d): 0x%x\n", slot, new)); - return 0; -} - -void -pcibr_release_device(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - uint64_t mask) -{ - pcibr_soft_slot_t slotp; - unsigned long s; - - slotp = &pcibr_soft->bs_slot[slot]; - - s = pcibr_lock(pcibr_soft); - - if (mask == BRIDGE_DEV_PMU_BITS) - slotp->bss_pmu_uctr--; - if (mask == BRIDGE_DEV_D32_BITS) - slotp->bss_d32_uctr--; - if (mask == BRIDGE_DEV_D64_BITS) - slotp->bss_d64_uctr--; - - pcibr_unlock(pcibr_soft, s); -} - - -/* ===================================================================== - * Bridge (pcibr) "Device Driver" entry points - */ - - -static int -pcibr_mmap(struct file * file, struct vm_area_struct * vma) -{ - vertex_hdl_t pcibr_vhdl = file->f_dentry->d_fsdata; - pcibr_soft_t pcibr_soft; - void *bridge; - unsigned long phys_addr; - int error = 0; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - bridge = pcibr_soft->bs_base; - phys_addr = (unsigned long)bridge & ~0xc000000000000000; /* Mask out the Uncache bits */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_RESERVED | VM_IO; - error = io_remap_page_range(vma, phys_addr, vma->vm_start, - vma->vm_end - vma->vm_start, - vma->vm_page_prot); - return error; -} - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -static int pcibr_mmap(struct file * file, struct vm_area_struct * vma); -struct file_operations pcibr_fops = { - .owner = THIS_MODULE, - .mmap = pcibr_mmap, -}; - - -/* This is special case code used by grio. There are plans to make - * this a bit more general in the future, but till then this should - * be sufficient. - */ -pciio_slot_t -pcibr_device_slot_get(vertex_hdl_t dev_vhdl) -{ - char devname[MAXDEVNAME]; - vertex_hdl_t tdev; - pciio_info_t pciio_info; - pciio_slot_t slot = PCIIO_SLOT_NONE; - - vertex_to_name(dev_vhdl, devname, MAXDEVNAME); - - /* run back along the canonical path - * until we find a PCI connection point. - */ - tdev = hwgraph_connectpt_get(dev_vhdl); - while (tdev != GRAPH_VERTEX_NONE) { - pciio_info = pciio_info_chk(tdev); - if (pciio_info) { - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - break; - } - hwgraph_vertex_unref(tdev); - tdev = hwgraph_connectpt_get(tdev); - } - hwgraph_vertex_unref(tdev); - - return slot; -} - -pcibr_info_t -pcibr_info_get(vertex_hdl_t vhdl) -{ - return (pcibr_info_t) pciio_info_get(vhdl); -} - -pcibr_info_t -pcibr_device_info_new( - pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - pciio_function_t rfunc, - pciio_vendor_id_t vendor, - pciio_device_id_t device) -{ - pcibr_info_t pcibr_info; - pciio_function_t func; - int ibit; - - func = (rfunc == PCIIO_FUNC_NONE) ? 0 : rfunc; - - /* - * Create a pciio_info_s for this device. pciio_device_info_new() - * will set the c_slot (which is suppose to represent the external - * slot (i.e the slot number silk screened on the back of the I/O - * brick)). So for PIC we need to adjust this "internal slot" num - * passed into us, into its external representation. See comment - * for the PCIBR_DEVICE_TO_SLOT macro for more information. - */ - pcibr_info = kmalloc(sizeof (*(pcibr_info)), GFP_KERNEL); - if ( !pcibr_info ) { - return NULL; - } - memset(pcibr_info, 0, sizeof (*(pcibr_info))); - - pciio_device_info_new(&pcibr_info->f_c, pcibr_soft->bs_vhdl, - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - rfunc, vendor, device); - pcibr_info->f_dev = slot; - - /* Set PCI bus number */ - pcibr_info->f_bus = pcibr_widget_to_bus(pcibr_soft->bs_vhdl); - - if (slot != PCIIO_SLOT_NONE) { - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - * - * XXX- allow pcibr_hints to override default - * XXX- allow ADMIN to override pcibr_hints - */ - for (ibit = 0; ibit < 4; ++ibit) - pcibr_info->f_ibit[ibit] = - (slot + 4 * ibit) & 7; - - /* - * Record the info in the sparse func info space. - */ - if (func < pcibr_soft->bs_slot[slot].bss_ninfo) - pcibr_soft->bs_slot[slot].bss_infos[func] = pcibr_info; - } - return pcibr_info; -} - - -/* - * pcibr_device_unregister - * This frees up any hardware resources reserved for this PCI device - * and removes any PCI infrastructural information setup for it. - * This is usually used at the time of shutting down of the PCI card. - */ -int -pcibr_device_unregister(vertex_hdl_t pconn_vhdl) -{ - pciio_info_t pciio_info; - vertex_hdl_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - int count_vchan0, count_vchan1; - unsigned long s; - int error_call; - int error = 0; - - pciio_info = pciio_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - /* Clear all the hardware xtalk resources for this device */ - xtalk_widgetdev_shutdown(pcibr_soft->bs_conn, slot); - - /* Flush all the rrbs */ - pcibr_rrb_flush(pconn_vhdl); - - /* - * If the RRB configuration for this slot has changed, set it - * back to the boot-time default - */ - if (pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] >= 0) { - - s = pcibr_lock(pcibr_soft); - - pcibr_soft->bs_rrb_res[slot] = pcibr_soft->bs_rrb_res[slot] + - pcibr_soft->bs_rrb_valid[slot][VCHAN0] + - pcibr_soft->bs_rrb_valid[slot][VCHAN1] + - pcibr_soft->bs_rrb_valid[slot][VCHAN2] + - pcibr_soft->bs_rrb_valid[slot][VCHAN3]; - - /* Free the rrbs allocated to this slot, both the normal & virtual */ - do_pcibr_rrb_free_all(pcibr_soft, slot); - - count_vchan0 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0]; - count_vchan1 = pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN1]; - - pcibr_unlock(pcibr_soft, s); - - pcibr_rrb_alloc(pconn_vhdl, &count_vchan0, &count_vchan1); - - } - - /* Flush the write buffers !! */ - error_call = pcibr_wrb_flush(pconn_vhdl); - - if (error_call) - error = error_call; - - /* Clear the information specific to the slot */ - error_call = pcibr_slot_info_free(pcibr_vhdl, slot); - - if (error_call) - error = error_call; - - return error; - -} - -/* - * pcibr_driver_reg_callback - * CDL will call this function for each device found in the PCI - * registry that matches the vendor/device IDs supported by - * the driver being registered. The device's connection vertex - * and the driver's attach function return status enable the - * slot's device status to be set. - */ -void -pcibr_driver_reg_callback(vertex_hdl_t pconn_vhdl, - int key1, int key2, int error) -{ - pciio_info_t pciio_info; - pcibr_info_t pcibr_info; - vertex_hdl_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - - /* Do not set slot status for vendor/device ID wildcard drivers */ - if ((key1 == -1) || (key2 == -1)) - return; - - pciio_info = pciio_info_get(pconn_vhdl); - pcibr_info = pcibr_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info->f_att_det_error = error; - -#ifdef CONFIG_HOTPLUG_PCI_SGI - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - - if (error) { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; - } else { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; - } -#endif /* CONFIG_HOTPLUG_PCI_SGI */ -} - -/* - * pcibr_driver_unreg_callback - * CDL will call this function for each device found in the PCI - * registry that matches the vendor/device IDs supported by - * the driver being unregistered. The device's connection vertex - * and the driver's detach function return status enable the - * slot's device status to be set. - */ -void -pcibr_driver_unreg_callback(vertex_hdl_t pconn_vhdl, - int key1, int key2, int error) -{ - pciio_info_t pciio_info; - pcibr_info_t pcibr_info; - vertex_hdl_t pcibr_vhdl; - pciio_slot_t slot; - pcibr_soft_t pcibr_soft; - - /* Do not set slot status for vendor/device ID wildcard drivers */ - if ((key1 == -1) || (key2 == -1)) - return; - - pciio_info = pciio_info_get(pconn_vhdl); - pcibr_info = pcibr_info_get(pconn_vhdl); - - pcibr_vhdl = pciio_info_master_get(pciio_info); - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info->f_att_det_error = error; -#ifdef CONFIG_HOTPLUG_PCI_SGI - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - - if (error) { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; - } else { - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; - } -#endif /* CONFIG_HOTPLUG_PCI_SGI */ -} - -/* - * pcibr_detach: - * Detach the bridge device from the hwgraph after cleaning out all the - * underlying vertices. - */ - -int -pcibr_detach(vertex_hdl_t xconn) -{ - pciio_slot_t slot; - vertex_hdl_t pcibr_vhdl; - pcibr_soft_t pcibr_soft; - unsigned long s; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DETACH, xconn, "pcibr_detach\n")); - - /* Get the bridge vertex from its xtalk connection point */ - if (hwgraph_traverse(xconn, EDGE_LBL_PCI, &pcibr_vhdl) != GRAPH_SUCCESS) - return 1; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - /* Disable the interrupts from the bridge */ - s = pcibr_lock(pcibr_soft); - pcireg_intr_enable_set(pcibr_soft, 0); - pcibr_unlock(pcibr_soft, s); - - /* Detach all the PCI devices talking to this bridge */ - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - pcibr_slot_detach(pcibr_vhdl, slot, 0, (char *)NULL, (int *)NULL); - } - - /* Unregister the no-slot connection point */ - pciio_device_info_unregister(pcibr_vhdl, - &(pcibr_soft->bs_noslot_info->f_c)); - - kfree(pcibr_soft->bs_name); - - /* Disconnect the error interrupt and free the xtalk resources - * associated with it. - */ - xtalk_intr_disconnect(pcibr_soft->bsi_err_intr); - xtalk_intr_free(pcibr_soft->bsi_err_intr); - - /* Clear the software state maintained by the bridge driver for this - * bridge. - */ - kfree(pcibr_soft); - - /* Remove the Bridge revision labelled info */ - (void)hwgraph_info_remove_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, NULL); - - return 0; -} - - -/* - * Set the Bridge's 32-bit PCI to XTalk Direct Map register to the most useful - * value we can determine. Note that we must use a single xid for all of: - * -direct-mapped 32-bit DMA accesses - * -direct-mapped 64-bit DMA accesses - * -DMA accesses through the PMU - * -interrupts - * This is the only way to guarantee that completion interrupts will reach a - * CPU after all DMA data has reached memory. - */ -void -pcibr_directmap_init(pcibr_soft_t pcibr_soft) -{ - paddr_t paddr; - iopaddr_t xbase; - uint64_t diroff; - cnodeid_t cnodeid = 0; /* We need api for diroff api */ - nasid_t nasid; - - nasid = cnodeid_to_nasid(cnodeid); - paddr = NODE_OFFSET(nasid) + 0; - - /* Assume that if we ask for a DMA mapping to zero the XIO host will - * transmute this into a request for the lowest hunk of memory. - */ - xbase = xtalk_dmatrans_addr(pcibr_soft->bs_conn, 0, paddr, PAGE_SIZE, 0); - - diroff = xbase >> BRIDGE_DIRMAP_OFF_ADDRSHFT; - pcireg_dirmap_diroff_set(pcibr_soft, diroff); - pcireg_dirmap_wid_set(pcibr_soft, pcibr_soft->bs_mxid); - pcibr_soft->bs_dir_xport = pcibr_soft->bs_mxid; - if (xbase == (512 << 20)) { /* 512Meg */ - pcireg_dirmap_add512_set(pcibr_soft); - pcibr_soft->bs_dir_xbase = (512 << 20); - } else { - pcireg_dirmap_add512_clr(pcibr_soft); - pcibr_soft->bs_dir_xbase = diroff << BRIDGE_DIRMAP_OFF_ADDRSHFT; - } -} - - -int -pcibr_asic_rev(vertex_hdl_t pconn_vhdl) -{ - vertex_hdl_t pcibr_vhdl; - int rc; - arbitrary_info_t ainfo; - - if (GRAPH_SUCCESS != - hwgraph_traverse(pconn_vhdl, EDGE_LBL_MASTER, &pcibr_vhdl)) - return -1; - - rc = hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &ainfo); - - /* - * Any hwgraph function that returns a vertex handle will implicity - * increment that vertex's reference count. The caller must explicity - * decrement the vertex's referece count after the last reference to - * that vertex. - * - * Decrement reference count incremented by call to hwgraph_traverse(). - * - */ - hwgraph_vertex_unref(pcibr_vhdl); - - if (rc != GRAPH_SUCCESS) - return -1; - - return (int) ainfo; -} - -/* ===================================================================== - * PIO MANAGEMENT - */ - -static iopaddr_t -pcibr_addr_pci_to_xio(vertex_hdl_t pconn_vhdl, - pciio_slot_t slot, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - unsigned bar; /* which BASE reg on device is decoding */ - iopaddr_t xio_addr = XIO_NOWHERE; - iopaddr_t base = 0; - iopaddr_t limit = 0; - - pciio_space_t wspace; /* which space device is decoding */ - iopaddr_t wbase; /* base of device decode on PCI */ - size_t wsize; /* size of device decode on PCI */ - - int try; /* DevIO(x) window scanning order control */ - int maxtry, halftry; - int win; /* which DevIO(x) window is being used */ - pciio_space_t mspace; /* target space for devio(x) register */ - iopaddr_t mbase; /* base of devio(x) mapped area on PCI */ - size_t msize; /* size of devio(x) mapped area on PCI */ - size_t mmask; /* addr bits stored in Device(x) */ - - unsigned long s; - - s = pcibr_lock(pcibr_soft); - - if (pcibr_soft->bs_slot[slot].has_host) { - slot = pcibr_soft->bs_slot[slot].host_slot; - pcibr_info = pcibr_soft->bs_slot[slot].bss_infos[0]; - - /* - * Special case for dual-slot pci devices such as ioc3 on IP27 - * baseio. In these cases, pconn_vhdl should never be for a pci - * function on a subordiate PCI bus, so we can safely reset pciio_info - * to be the info struct embedded in pcibr_info. Failure to do this - * results in using a bogus pciio_info_t for calculations done later - * in this routine. - */ - - pciio_info = &pcibr_info->f_c; - } - if (space == PCIIO_SPACE_NONE) - goto done; - - if (space == PCIIO_SPACE_CFG) { - /* - * Usually, the first mapping - * established to a PCI device - * is to its config space. - * - * In any case, we definitely - * do NOT need to worry about - * PCI BASE registers, and - * MUST NOT attempt to point - * the DevIO(x) window at - * this access ... - */ - if (((flags & PCIIO_BYTE_STREAM) == 0) && - ((pci_addr + req_size) <= BRIDGE_TYPE0_CFG_FUNC_OFF)) - xio_addr = pci_addr + PCIBR_TYPE0_CFG_DEV(pcibr_soft, slot); - - goto done; - } - if (space == PCIIO_SPACE_ROM) { - /* PIO to the Expansion Rom. - * Driver is responsible for - * enabling and disabling - * decodes properly. - */ - wbase = pciio_info->c_rbase; - wsize = pciio_info->c_rsize; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - pci_addr += wbase; - space = PCIIO_SPACE_MEM; - } - /* - * reduce window mappings to raw - * space mappings (maybe allocating - * windows), and try for DevIO(x) - * usage (setting it if it is available). - */ - bar = space - PCIIO_SPACE_WIN0; - if (bar < 6) { - wspace = pciio_info->c_window[bar].w_space; - if (wspace == PCIIO_SPACE_NONE) - goto done; - - /* get PCI base and size */ - wbase = pciio_info->c_window[bar].w_base; - wsize = pciio_info->c_window[bar].w_size; - - /* - * While the driver should know better - * than to attempt to map more space - * than the device is decoding, he might - * do it; better to bail out here. - */ - if ((pci_addr + req_size) > wsize) - goto done; - - /* shift from window relative to - * decoded space relative. - */ - pci_addr += wbase; - space = wspace; - } else - bar = -1; - - /* Scan all the DevIO(x) windows twice looking for one - * that can satisfy our request. The first time through, - * only look at assigned windows; the second time, also - * look at PCIIO_SPACE_NONE windows. Arrange the order - * so we always look at our own window first. - * - * We will not attempt to satisfy a single request - * by concatinating multiple windows. - */ - maxtry = PCIBR_NUM_SLOTS(pcibr_soft) * 2; - halftry = PCIBR_NUM_SLOTS(pcibr_soft) - 1; - for (try = 0; try < maxtry; ++try) { - uint64_t devreg; - unsigned offset; - - /* calculate win based on slot, attempt, and max possible - devices on bus */ - win = (try + slot) % PCIBR_NUM_SLOTS(pcibr_soft); - - /* If this DevIO(x) mapping area can provide - * a mapping to this address, use it. - */ - msize = (win < 2) ? 0x200000 : 0x100000; - mmask = -msize; - if (space != PCIIO_SPACE_IO) - mmask &= 0x3FFFFFFF; - - offset = pci_addr & (msize - 1); - - /* If this window can't possibly handle that request, - * go on to the next window. - */ - if (((pci_addr & (msize - 1)) + req_size) > msize) - continue; - - devreg = pcibr_soft->bs_slot[win].bss_device; - - /* Is this window "nailed down"? - * If not, maybe we can use it. - * (only check this the second time through) - */ - mspace = pcibr_soft->bs_slot[win].bss_devio.bssd_space; - if ((try > halftry) && (mspace == PCIIO_SPACE_NONE)) { - - /* If this is the primary DevIO(x) window - * for some other device, skip it. - */ - if ((win != slot) && - (PCIIO_VENDOR_ID_NONE != - pcibr_soft->bs_slot[win].bss_vendor_id)) - continue; - - /* It's a free window, and we fit in it. - * Set up Device(win) to our taste. - */ - mbase = pci_addr & mmask; - - /* check that we would really get from - * here to there. - */ - if ((mbase | offset) != pci_addr) - continue; - - devreg &= ~BRIDGE_DEV_OFF_MASK; - if (space != PCIIO_SPACE_IO) - devreg |= BRIDGE_DEV_DEV_IO_MEM; - else - devreg &= ~BRIDGE_DEV_DEV_IO_MEM; - devreg |= (mbase >> 20) & BRIDGE_DEV_OFF_MASK; - - /* default is WORD_VALUES. - * if you specify both, - * operation is undefined. - */ - if (flags & PCIIO_BYTE_STREAM) - devreg |= BRIDGE_DEV_DEV_SWAP; - else - devreg &= ~BRIDGE_DEV_DEV_SWAP; - - if (pcibr_soft->bs_slot[win].bss_device != devreg) { - pcireg_device_set(pcibr_soft, win, devreg); - pcibr_soft->bs_slot[win].bss_device = devreg; - pcireg_tflush_get(pcibr_soft); - - PCIBR_DEBUG((PCIBR_DEBUG_DEVREG, pconn_vhdl, - "pcibr_addr_pci_to_xio: Device(%d): 0x%x\n", - win, devreg)); - } - pcibr_soft->bs_slot[win].bss_devio.bssd_space = space; - pcibr_soft->bs_slot[win].bss_devio.bssd_base = mbase; - xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); - - /* Increment this DevIO's use count */ - pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; - - /* Save the DevIO register index used to access this BAR */ - if (bar != -1) - pcibr_info->f_window[bar].w_devio_index = win; - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_addr_pci_to_xio: map to space %s [0x%lx..0x%lx] " - "for slot %d allocates DevIO(%d) Device(%d) set to %lx\n", - pci_space[space], pci_addr, pci_addr + req_size - 1, - slot, win, win, devreg)); - - goto done; - } /* endif DevIO(x) not pointed */ - mbase = pcibr_soft->bs_slot[win].bss_devio.bssd_base; - - /* Now check for request incompat with DevIO(x) - */ - if ((mspace != space) || - (pci_addr < mbase) || - ((pci_addr + req_size) > (mbase + msize)) || - ((flags & PCIIO_BYTE_STREAM) && !(devreg & BRIDGE_DEV_DEV_SWAP)) || - (!(flags & PCIIO_BYTE_STREAM) && (devreg & BRIDGE_DEV_DEV_SWAP))) - continue; - - /* DevIO(x) window is pointed at PCI space - * that includes our target. Calculate the - * final XIO address, release the lock and - * return. - */ - xio_addr = PCIBR_BRIDGE_DEVIO(pcibr_soft, win) + (pci_addr - mbase); - - /* Increment this DevIO's use count */ - pcibr_soft->bs_slot[win].bss_devio.bssd_ref_cnt++; - - /* Save the DevIO register index used to access this BAR */ - if (bar != -1) - pcibr_info->f_window[bar].w_devio_index = win; - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_addr_pci_to_xio: map to space %s [0x%lx..0x%lx] " - "for slot %d uses DevIO(%d)\n", pci_space[space], - pci_addr, pci_addr + req_size - 1, slot, win)); - goto done; - } - - switch (space) { - /* - * Accesses to device decode - * areas that do a not fit - * within the DevIO(x) space are - * modified to be accesses via - * the direct mapping areas. - * - * If necessary, drivers can - * explicitly ask for mappings - * into these address spaces, - * but this should never be needed. - */ - case PCIIO_SPACE_MEM: /* "mem space" */ - case PCIIO_SPACE_MEM32: /* "mem, use 32-bit-wide bus" */ - if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ - base = PICBRIDGE0_PCI_MEM32_BASE; - limit = PICBRIDGE0_PCI_MEM32_LIMIT; - } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ - base = PICBRIDGE1_PCI_MEM32_BASE; - limit = PICBRIDGE1_PCI_MEM32_LIMIT; - } else { - printk("pcibr_addr_pci_to_xio(): unknown bridge type"); - return (iopaddr_t)0; - } - - if ((pci_addr + base + req_size - 1) <= limit) - xio_addr = pci_addr + base; - break; - - case PCIIO_SPACE_MEM64: /* "mem, use 64-bit-wide bus" */ - if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { /* PIC bus 0 */ - base = PICBRIDGE0_PCI_MEM64_BASE; - limit = PICBRIDGE0_PCI_MEM64_LIMIT; - } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { /* PIC bus 1 */ - base = PICBRIDGE1_PCI_MEM64_BASE; - limit = PICBRIDGE1_PCI_MEM64_LIMIT; - } else { - printk("pcibr_addr_pci_to_xio(): unknown bridge type"); - return (iopaddr_t)0; - } - - if ((pci_addr + base + req_size - 1) <= limit) - xio_addr = pci_addr + base; - break; - - case PCIIO_SPACE_IO: /* "i/o space" */ - /* - * PIC bridges do not support big-window aliases into PCI I/O space - */ - xio_addr = XIO_NOWHERE; - break; - } - - /* Check that "Direct PIO" byteswapping matches, - * try to change it if it does not. - */ - if (xio_addr != XIO_NOWHERE) { - unsigned bst; /* nonzero to set bytestream */ - unsigned *bfp; /* addr of record of how swapper is set */ - uint64_t swb; /* which control bit to mung */ - unsigned bfo; /* current swapper setting */ - unsigned bfn; /* desired swapper setting */ - - bfp = ((space == PCIIO_SPACE_IO) - ? (&pcibr_soft->bs_pio_end_io) - : (&pcibr_soft->bs_pio_end_mem)); - - bfo = *bfp; - - bst = flags & PCIIO_BYTE_STREAM; - - bfn = bst ? PCIIO_BYTE_STREAM : PCIIO_WORD_VALUES; - - if (bfn == bfo) { /* we already match. */ - ; - } else if (bfo != 0) { /* we have a conflict. */ - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_addr_pci_to_xio: swap conflict in %s, " - "was%s%s, want%s%s\n", pci_space[space], - bfo & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfo & PCIIO_WORD_VALUES ? " WORD_VALUES" : "", - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "")); - xio_addr = XIO_NOWHERE; - } else { /* OK to make the change. */ - swb = (space == PCIIO_SPACE_IO) ? 0: BRIDGE_CTRL_MEM_SWAP; - if (bst) { - pcireg_control_bit_set(pcibr_soft, swb); - } else { - pcireg_control_bit_clr(pcibr_soft, swb); - } - - *bfp = bfn; /* record the assignment */ - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_addr_pci_to_xio: swap for %s set to%s%s\n", - pci_space[space], - bfn & PCIIO_BYTE_STREAM ? " BYTE_STREAM" : "", - bfn & PCIIO_WORD_VALUES ? " WORD_VALUES" : "")); - } - } - done: - pcibr_unlock(pcibr_soft, s); - return xio_addr; -} - -/*ARGSUSED6 */ -pcibr_piomap_t -pcibr_piomap_alloc(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - size_t req_size_max, - unsigned flags) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - - pcibr_piomap_t *mapptr; - pcibr_piomap_t maplist; - pcibr_piomap_t pcibr_piomap; - iopaddr_t xio_addr; - xtalk_piomap_t xtalk_piomap; - unsigned long s; - - /* Make sure that the req sizes are non-zero */ - if ((req_size < 1) || (req_size_max < 1)) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piomap_alloc: req_size | req_size_max < 1\n")); - return NULL; - } - - /* - * Code to translate slot/space/addr - * into xio_addr is common between - * this routine and pcibr_piotrans_addr. - */ - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piomap_alloc: xio_addr == XIO_NOWHERE\n")); - return NULL; - } - - /* Check the piomap list to see if there is already an allocated - * piomap entry but not in use. If so use that one. Otherwise - * allocate a new piomap entry and add it to the piomap list - */ - mapptr = &(pcibr_info->f_piomap); - - s = pcibr_lock(pcibr_soft); - for (pcibr_piomap = *mapptr; - pcibr_piomap != NULL; - pcibr_piomap = pcibr_piomap->bp_next) { - if (pcibr_piomap->bp_mapsz == 0) - break; - } - - if (pcibr_piomap) - mapptr = NULL; - else { - pcibr_unlock(pcibr_soft, s); - pcibr_piomap = kmalloc(sizeof (*(pcibr_piomap)), GFP_KERNEL); - if ( !pcibr_piomap ) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piomap_alloc: malloc fails\n")); - return NULL; - } - memset(pcibr_piomap, 0, sizeof (*(pcibr_piomap))); - } - - pcibr_piomap->bp_dev = pconn_vhdl; - pcibr_piomap->bp_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, pciio_slot); - pcibr_piomap->bp_flags = flags; - pcibr_piomap->bp_space = space; - pcibr_piomap->bp_pciaddr = pci_addr; - pcibr_piomap->bp_mapsz = req_size; - pcibr_piomap->bp_soft = pcibr_soft; - pcibr_piomap->bp_toc = ATOMIC_INIT(0); - - if (mapptr) { - s = pcibr_lock(pcibr_soft); - maplist = *mapptr; - pcibr_piomap->bp_next = maplist; - *mapptr = pcibr_piomap; - } - pcibr_unlock(pcibr_soft, s); - - - if (pcibr_piomap) { - xtalk_piomap = - xtalk_piomap_alloc(xconn_vhdl, 0, - xio_addr, - req_size, req_size_max, - flags & PIOMAP_FLAGS); - if (xtalk_piomap) { - pcibr_piomap->bp_xtalk_addr = xio_addr; - pcibr_piomap->bp_xtalk_pio = xtalk_piomap; - } else { - pcibr_piomap->bp_mapsz = 0; - pcibr_piomap = 0; - } - } - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piomap_alloc: map=0x%lx\n", pcibr_piomap)); - - return pcibr_piomap; -} - -/*ARGSUSED */ -void -pcibr_piomap_free(pcibr_piomap_t pcibr_piomap) -{ - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, - "pcibr_piomap_free: map=0x%lx\n", pcibr_piomap)); - - xtalk_piomap_free(pcibr_piomap->bp_xtalk_pio); - pcibr_piomap->bp_xtalk_pio = 0; - pcibr_piomap->bp_mapsz = 0; -} - -/*ARGSUSED */ -caddr_t -pcibr_piomap_addr(pcibr_piomap_t pcibr_piomap, - iopaddr_t pci_addr, - size_t req_size) -{ - caddr_t addr; - addr = xtalk_piomap_addr(pcibr_piomap->bp_xtalk_pio, - pcibr_piomap->bp_xtalk_addr + - pci_addr - pcibr_piomap->bp_pciaddr, - req_size); - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, - "pcibr_piomap_addr: map=0x%lx, addr=0x%lx\n", - pcibr_piomap, addr)); - - return addr; -} - -/*ARGSUSED */ -void -pcibr_piomap_done(pcibr_piomap_t pcibr_piomap) -{ - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pcibr_piomap->bp_dev, - "pcibr_piomap_done: map=0x%lx\n", pcibr_piomap)); - xtalk_piomap_done(pcibr_piomap->bp_xtalk_pio); -} - -/*ARGSUSED */ -caddr_t -pcibr_piotrans_addr(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - iopaddr_t pci_addr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - - iopaddr_t xio_addr; - caddr_t addr; - - xio_addr = pcibr_addr_pci_to_xio(pconn_vhdl, pciio_slot, space, pci_addr, req_size, flags); - - if (xio_addr == XIO_NOWHERE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIODIR, pconn_vhdl, - "pcibr_piotrans_addr: xio_addr == XIO_NOWHERE\n")); - return NULL; - } - - addr = xtalk_piotrans_addr(xconn_vhdl, 0, xio_addr, req_size, flags & PIOMAP_FLAGS); - PCIBR_DEBUG((PCIBR_DEBUG_PIODIR, pconn_vhdl, - "pcibr_piotrans_addr: xio_addr=0x%lx, addr=0x%lx\n", - xio_addr, addr)); - return addr; -} - -/* - * PIO Space allocation and management. - * Allocate and Manage the PCI PIO space (mem and io space) - * This routine is pretty simplistic at this time, and - * does pretty trivial management of allocation and freeing. - * The current scheme is prone for fragmentation. - * Change the scheme to use bitmaps. - */ - -/*ARGSUSED */ -iopaddr_t -pcibr_piospace_alloc(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - pciio_space_t space, - size_t req_size, - size_t alignment) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_info_t pciio_info = &pcibr_info->f_c; - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - pciio_piospace_t piosp; - unsigned long s; - - iopaddr_t start_addr; - size_t align_mask; - - /* - * Check for proper alignment - */ - ASSERT(alignment >= PAGE_SIZE); - ASSERT((alignment & (alignment - 1)) == 0); - - align_mask = alignment - 1; - s = pcibr_lock(pcibr_soft); - - /* - * First look if a previously allocated chunk exists. - */ - piosp = pcibr_info->f_piospace; - if (piosp) { - /* - * Look through the list for a right sized free chunk. - */ - do { - if (piosp->free && - (piosp->space == space) && - (piosp->count >= req_size) && - !(piosp->start & align_mask)) { - piosp->free = 0; - pcibr_unlock(pcibr_soft, s); - return piosp->start; - } - piosp = piosp->next; - } while (piosp); - } - ASSERT(!piosp); - - /* - * Allocate PCI bus address, usually for the Universe chip driver; - * do not pass window info since the actual PCI bus address - * space will never be freed. The space may be reused after it - * is logically released by pcibr_piospace_free(). - */ - switch (space) { - case PCIIO_SPACE_IO: - start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL, - PCIIO_SPACE_IO, - 0, req_size, alignment); - break; - - case PCIIO_SPACE_MEM: - case PCIIO_SPACE_MEM32: - start_addr = pcibr_bus_addr_alloc(pcibr_soft, NULL, - PCIIO_SPACE_MEM32, - 0, req_size, alignment); - break; - - default: - ASSERT(0); - pcibr_unlock(pcibr_soft, s); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piospace_alloc: unknown space %d\n", space)); - return 0; - } - - /* - * If too big a request, reject it. - */ - if (!start_addr) { - pcibr_unlock(pcibr_soft, s); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piospace_alloc: request 0x%lx to big\n", req_size)); - return 0; - } - - piosp = kmalloc(sizeof (*(piosp)), GFP_KERNEL); - if ( !piosp ) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piospace_alloc: malloc fails\n")); - return 0; - } - memset(piosp, 0, sizeof (*(piosp))); - - piosp->free = 0; - piosp->space = space; - piosp->start = start_addr; - piosp->count = req_size; - piosp->next = pcibr_info->f_piospace; - pcibr_info->f_piospace = piosp; - - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piospace_alloc: piosp=0x%lx\n", piosp)); - - return start_addr; -} - -#define ERR_MSG "!Device %s freeing size (0x%lx) different than allocated (0x%lx)" -/*ARGSUSED */ -void -pcibr_piospace_free(vertex_hdl_t pconn_vhdl, - pciio_space_t space, - iopaddr_t pciaddr, - size_t req_size) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - pciio_piospace_t piosp; - unsigned long s; - char name[1024]; - - /* - * Look through the bridge data structures for the pciio_piospace_t - * structure corresponding to 'pciaddr' - */ - s = pcibr_lock(pcibr_soft); - piosp = pcibr_info->f_piospace; - while (piosp) { - /* - * Piospace free can only be for the complete - * chunk and not parts of it.. - */ - if (piosp->start == pciaddr) { - if (piosp->count == req_size) - break; - /* - * Improper size passed for freeing.. - * Print a message and break; - */ - hwgraph_vertex_name_get(pconn_vhdl, name, 1024); - printk(KERN_WARNING "pcibr_piospace_free: error"); - printk(KERN_WARNING "Device %s freeing size (0x%lx) different than allocated (0x%lx)", - name, req_size, piosp->count); - printk(KERN_WARNING "Freeing 0x%lx instead", piosp->count); - break; - } - piosp = piosp->next; - } - - if (!piosp) { - printk(KERN_WARNING - "pcibr_piospace_free: Address 0x%lx size 0x%lx - No match\n", - pciaddr, req_size); - pcibr_unlock(pcibr_soft, s); - return; - } - piosp->free = 1; - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG((PCIBR_DEBUG_PIOMAP, pconn_vhdl, - "pcibr_piospace_free: piosp=0x%lx\n", piosp)); - return; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * The Bridge ASIC provides three methods of doing - * DMA: via a "direct map" register available in - * 32-bit PCI space (which selects a contiguous 2G - * address space on some other widget), via - * "direct" addressing via 64-bit PCI space (all - * destination information comes from the PCI - * address, including transfer attributes), and via - * a "mapped" region that allows a bunch of - * different small mappings to be established with - * the PMU. - * - * For efficiency, we most prefer to use the 32-bit - * direct mapping facility, since it requires no - * resource allocations. The advantage of using the - * PMU over the 64-bit direct is that single-cycle - * PCI addressing can be used; the advantage of - * using 64-bit direct over PMU addressing is that - * we do not have to allocate entries in the PMU. - */ - -/* - * Convert PCI-generic software flags and Bridge-specific software flags - * into Bridge-specific Direct Map attribute bits. - */ -static iopaddr_t -pcibr_flags_to_d64(unsigned flags, pcibr_soft_t pcibr_soft) -{ - iopaddr_t attributes = 0; - - /* Sanity check: Bridge only allows use of VCHAN1 via 64-bit addrs */ -#ifdef LATER - ASSERT_ALWAYS(!(flags & PCIBR_VCHAN1) || (flags & PCIIO_DMA_A64)); -#endif - - /* Generic macro flags - */ - if (flags & PCIIO_DMA_DATA) { /* standard data channel */ - attributes &= ~PCI64_ATTR_BAR; /* no barrier bit */ - attributes |= PCI64_ATTR_PREF; /* prefetch on */ - } - if (flags & PCIIO_DMA_CMD) { /* standard command channel */ - attributes |= PCI64_ATTR_BAR; /* barrier bit on */ - attributes &= ~PCI64_ATTR_PREF; /* disable prefetch */ - } - /* Generic detail flags - */ - if (flags & PCIIO_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIIO_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - /* the swap bit is in the address attributes for xbridge */ - if (flags & PCIIO_BYTE_STREAM) - attributes |= PCI64_ATTR_SWAP; - if (flags & PCIIO_WORD_VALUES) - attributes &= ~PCI64_ATTR_SWAP; - - /* Provider-specific flags - */ - if (flags & PCIBR_BARRIER) - attributes |= PCI64_ATTR_BAR; - if (flags & PCIBR_NOBARRIER) - attributes &= ~PCI64_ATTR_BAR; - - if (flags & PCIBR_PREFETCH) - attributes |= PCI64_ATTR_PREF; - if (flags & PCIBR_NOPREFETCH) - attributes &= ~PCI64_ATTR_PREF; - - if (flags & PCIBR_PRECISE) - attributes |= PCI64_ATTR_PREC; - if (flags & PCIBR_NOPRECISE) - attributes &= ~PCI64_ATTR_PREC; - - if (flags & PCIBR_VCHAN1) - attributes |= PCI64_ATTR_VIRTUAL; - if (flags & PCIBR_VCHAN0) - attributes &= ~PCI64_ATTR_VIRTUAL; - - /* PIC in PCI-X mode only supports barrier & swap */ - if (IS_PCIX(pcibr_soft)) { - attributes &= (PCI64_ATTR_BAR | PCI64_ATTR_SWAP); - } - - return attributes; -} - -/*ARGSUSED */ -pcibr_dmamap_t -pcibr_dmamap_alloc(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - size_t req_size_max, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t slot; - xwidgetnum_t xio_port; - - xtalk_dmamap_t xtalk_dmamap; - pcibr_dmamap_t pcibr_dmamap; - int ate_count; - int ate_index; - int vchan = VCHAN0; - unsigned long s; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - /* - * On SNIA64, these maps are pre-allocated because pcibr_dmamap_alloc() - * can be called within an interrupt thread. - */ - s = pcibr_lock(pcibr_soft); - pcibr_dmamap = (pcibr_dmamap_t)get_free_pciio_dmamap(pcibr_soft->bs_vhdl); - pcibr_unlock(pcibr_soft, s); - - if (!pcibr_dmamap) - return 0; - - xtalk_dmamap = xtalk_dmamap_alloc(xconn_vhdl, dev_desc, req_size_max, - flags & DMAMAP_FLAGS); - if (!xtalk_dmamap) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, - "pcibr_dmamap_alloc: xtalk_dmamap_alloc failed\n")); - free_pciio_dmamap(pcibr_dmamap); - return 0; - } - xio_port = pcibr_soft->bs_mxid; - slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - - pcibr_dmamap->bd_dev = pconn_vhdl; - pcibr_dmamap->bd_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot); - pcibr_dmamap->bd_soft = pcibr_soft; - pcibr_dmamap->bd_xtalk = xtalk_dmamap; - pcibr_dmamap->bd_max_size = req_size_max; - pcibr_dmamap->bd_xio_port = xio_port; - - if (flags & PCIIO_DMA_A64) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D64_BITS)) { - iopaddr_t pci_addr; - int have_rrbs; - int min_rrbs; - - /* Device is capable of A64 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - */ - - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_pci_addr = pci_addr; - - /* If in PCI mode, make sure we have an RRB (or two). - */ - if (IS_PCI(pcibr_soft) && - !(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - if (flags & PCIBR_VCHAN1) - vchan = VCHAN1; - have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - pcibr_rrb_alloc_more(pcibr_soft, slot, vchan, - min_rrbs - have_rrbs); - } - } - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmamap_alloc: using direct64, map=0x%lx\n", - pcibr_dmamap)); - return pcibr_dmamap; - } - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmamap_alloc: unable to use direct64\n")); - - /* PIC in PCI-X mode only supports 64-bit direct mapping so - * don't fall thru and try 32-bit direct mapping or 32-bit - * page mapping - */ - if (IS_PCIX(pcibr_soft)) { - kfree(pcibr_dmamap); - return 0; - } - - flags &= ~PCIIO_DMA_A64; - } - if (flags & PCIIO_FIXED) { - /* warning: mappings may fail later, - * if direct32 can't get to the address. - */ - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_D32_BITS)) { - /* User desires DIRECT A32 operations, - * and the attributes of the DMA are - * consistent with any previous DMA - * mappings using shared resources. - * Mapping calls may fail if target - * is outside the direct32 range. - */ - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmamap_alloc: using direct32, map=0x%lx\n", - pcibr_dmamap)); - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_xio_addr = pcibr_soft->bs_dir_xbase; - pcibr_dmamap->bd_pci_addr = PCI32_DIRECT_BASE; - return pcibr_dmamap; - } - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmamap_alloc: unable to use direct32\n")); - - /* If the user demands FIXED and we can't - * give it to him, fail. - */ - xtalk_dmamap_free(xtalk_dmamap); - free_pciio_dmamap(pcibr_dmamap); - return 0; - } - /* - * Allocate Address Translation Entries from the mapping RAM. - * Unless the PCIBR_NO_ATE_ROUNDUP flag is specified, - * the maximum number of ATEs is based on the worst-case - * scenario, where the requested target is in the - * last byte of an ATE; thus, mapping IOPGSIZE+2 - * does end up requiring three ATEs. - */ - if (!(flags & PCIBR_NO_ATE_ROUNDUP)) { - ate_count = IOPG((IOPGSIZE - 1) /* worst case start offset */ - +req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } else { /* assume requested target is page aligned */ - ate_count = IOPG(req_size_max /* max mapping bytes */ - - 1) + 1; /* round UP */ - } - - ate_index = pcibr_ate_alloc(pcibr_soft, ate_count, &pcibr_dmamap->resource); - - if (ate_index != -1) { - if (!pcibr_try_set_device(pcibr_soft, slot, flags, BRIDGE_DEV_PMU_BITS)) { - bridge_ate_t ate_proto; - int have_rrbs; - int min_rrbs; - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pconn_vhdl, - "pcibr_dmamap_alloc: using PMU, ate_index=%d, " - "pcibr_dmamap=0x%lx\n", ate_index, pcibr_dmamap)); - - ate_proto = pcibr_flags_to_ate(pcibr_soft, flags); - - pcibr_dmamap->bd_flags = flags; - pcibr_dmamap->bd_pci_addr = - PCI32_MAPPED_BASE + IOPGSIZE * ate_index; - - if (flags & PCIIO_BYTE_STREAM) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - /* - * If swap was set in bss_device in pcibr_endian_set() - * we need to change the address bit. - */ - if (pcibr_soft->bs_slot[slot].bss_device & - BRIDGE_DEV_SWAP_PMU) - ATE_SWAP_ON(pcibr_dmamap->bd_pci_addr); - if (flags & PCIIO_WORD_VALUES) - ATE_SWAP_OFF(pcibr_dmamap->bd_pci_addr); - pcibr_dmamap->bd_xio_addr = 0; - pcibr_dmamap->bd_ate_ptr = pcibr_ate_addr(pcibr_soft, ate_index); - pcibr_dmamap->bd_ate_index = ate_index; - pcibr_dmamap->bd_ate_count = ate_count; - pcibr_dmamap->bd_ate_proto = ate_proto; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[slot][vchan]; - if (have_rrbs < 2) { - if (ate_proto & ATE_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - pcibr_rrb_alloc_more(pcibr_soft, slot, vchan, - min_rrbs - have_rrbs); - } - } - return pcibr_dmamap; - } - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, - "pcibr_dmamap_alloc: PMU use failed, ate_index=%d\n", - ate_index)); - - pcibr_ate_free(pcibr_soft, ate_index, ate_count, &pcibr_dmamap->resource); - } - /* total failure: sorry, you just can't - * get from here to there that way. - */ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pconn_vhdl, - "pcibr_dmamap_alloc: complete failure.\n")); - xtalk_dmamap_free(xtalk_dmamap); - free_pciio_dmamap(pcibr_dmamap); - return 0; -} - -/*ARGSUSED */ -void -pcibr_dmamap_free(pcibr_dmamap_t pcibr_dmamap) -{ - pcibr_soft_t pcibr_soft = pcibr_dmamap->bd_soft; - pciio_slot_t slot = PCIBR_SLOT_TO_DEVICE(pcibr_soft, - pcibr_dmamap->bd_slot); - - xtalk_dmamap_free(pcibr_dmamap->bd_xtalk); - - if (pcibr_dmamap->bd_flags & PCIIO_DMA_A64) { - pcibr_release_device(pcibr_soft, slot, BRIDGE_DEV_D64_BITS); - } - if (pcibr_dmamap->bd_ate_count) { - pcibr_ate_free(pcibr_dmamap->bd_soft, - pcibr_dmamap->bd_ate_index, - pcibr_dmamap->bd_ate_count, - &pcibr_dmamap->resource); - pcibr_release_device(pcibr_soft, slot, XBRIDGE_DEV_PMU_BITS); - } - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_free: pcibr_dmamap=0x%lx\n", pcibr_dmamap)); - - free_pciio_dmamap(pcibr_dmamap); -} - -/* - * pcibr_addr_xio_to_pci: given a PIO range, hand - * back the corresponding base PCI MEM address; - * this is used to short-circuit DMA requests that - * loop back onto this PCI bus. - */ -static iopaddr_t -pcibr_addr_xio_to_pci(pcibr_soft_t soft, - iopaddr_t xio_addr, - size_t req_size) -{ - iopaddr_t xio_lim = xio_addr + req_size - 1; - iopaddr_t pci_addr; - pciio_slot_t slot; - - if (IS_PIC_BUSNUM_SOFT(soft, 0)) { - if ((xio_addr >= PICBRIDGE0_PCI_MEM32_BASE) && - (xio_lim <= PICBRIDGE0_PCI_MEM32_LIMIT)) { - pci_addr = xio_addr - PICBRIDGE0_PCI_MEM32_BASE; - return pci_addr; - } - if ((xio_addr >= PICBRIDGE0_PCI_MEM64_BASE) && - (xio_lim <= PICBRIDGE0_PCI_MEM64_LIMIT)) { - pci_addr = xio_addr - PICBRIDGE0_PCI_MEM64_BASE; - return pci_addr; - } - } else if (IS_PIC_BUSNUM_SOFT(soft, 1)) { - if ((xio_addr >= PICBRIDGE1_PCI_MEM32_BASE) && - (xio_lim <= PICBRIDGE1_PCI_MEM32_LIMIT)) { - pci_addr = xio_addr - PICBRIDGE1_PCI_MEM32_BASE; - return pci_addr; - } - if ((xio_addr >= PICBRIDGE1_PCI_MEM64_BASE) && - (xio_lim <= PICBRIDGE1_PCI_MEM64_LIMIT)) { - pci_addr = xio_addr - PICBRIDGE1_PCI_MEM64_BASE; - return pci_addr; - } - } else { - printk("pcibr_addr_xio_to_pci(): unknown bridge type"); - return (iopaddr_t)0; - } - for (slot = soft->bs_min_slot; slot < PCIBR_NUM_SLOTS(soft); ++slot) - if ((xio_addr >= PCIBR_BRIDGE_DEVIO(soft, slot)) && - (xio_lim < PCIBR_BRIDGE_DEVIO(soft, slot + 1))) { - uint64_t dev; - - dev = soft->bs_slot[slot].bss_device; - pci_addr = dev & BRIDGE_DEV_OFF_MASK; - pci_addr <<= BRIDGE_DEV_OFF_ADDR_SHFT; - pci_addr += xio_addr - PCIBR_BRIDGE_DEVIO(soft, slot); - return (dev & BRIDGE_DEV_DEV_IO_MEM) ? pci_addr : PCI_NOWHERE; - } - return 0; -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmamap_addr(pcibr_dmamap_t pcibr_dmamap, - paddr_t paddr, - size_t req_size) -{ - pcibr_soft_t pcibr_soft; - iopaddr_t xio_addr; - xwidgetnum_t xio_port; - iopaddr_t pci_addr; - unsigned flags; - - ASSERT(pcibr_dmamap != NULL); - ASSERT(req_size > 0); - ASSERT(req_size <= pcibr_dmamap->bd_max_size); - - pcibr_soft = pcibr_dmamap->bd_soft; - - flags = pcibr_dmamap->bd_flags; - - xio_addr = xtalk_dmamap_addr(pcibr_dmamap->bd_xtalk, paddr, req_size); - if (XIO_PACKED(xio_addr)) { - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - } else - xio_port = pcibr_dmamap->bd_xio_port; - - /* If this DMA is to an address that - * refers back to this Bridge chip, - * reduce it back to the correct - * PCI MEM address. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - } else if (flags & PCIIO_DMA_A64) { - /* A64 DMA: - * always use 64-bit direct mapping, - * which always works. - * Device(x) was set up during - * dmamap allocation. - */ - - /* attributes are already bundled up into bd_pci_addr. - */ - pci_addr = pcibr_dmamap->bd_pci_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT) - | xio_addr; - - /* Bridge Hardware WAR #482836: - * If the transfer is not cache aligned - * and the Bridge Rev is <= B, force - * prefetch to be off. - */ - if (flags & PCIBR_NOPREFETCH) - pci_addr &= ~PCI64_ATTR_PREF; - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, - pcibr_dmamap->bd_dev, - "pcibr_dmamap_addr: (direct64): wanted paddr [0x%lx..0x%lx] " - "XIO port 0x%x offset 0x%lx, returning PCI 0x%lx\n", - paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr)); - - } else if (flags & PCIIO_FIXED) { - /* A32 direct DMA: - * always use 32-bit direct mapping, - * which may fail. - * Device(x) was set up during - * dmamap allocation. - */ - - if (xio_port != pcibr_soft->bs_dir_xport) - pci_addr = 0; /* wrong DIDN */ - else if (xio_addr < pcibr_dmamap->bd_xio_addr) - pci_addr = 0; /* out of range */ - else if ((xio_addr + req_size) > - (pcibr_dmamap->bd_xio_addr + BRIDGE_DMA_DIRECT_SIZE)) - pci_addr = 0; /* out of range */ - else - pci_addr = pcibr_dmamap->bd_pci_addr + - xio_addr - pcibr_dmamap->bd_xio_addr; - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP | PCIBR_DEBUG_DMADIR, - pcibr_dmamap->bd_dev, - "pcibr_dmamap_addr (direct32): wanted paddr [0x%lx..0x%lx] " - "XIO port 0x%x offset 0x%lx, returning PCI 0x%lx\n", - paddr, paddr + req_size - 1, xio_port, xio_addr, pci_addr)); - - } else { - iopaddr_t offset = IOPGOFF(xio_addr); - bridge_ate_t ate_proto = pcibr_dmamap->bd_ate_proto; - int ate_count = IOPG(offset + req_size - 1) + 1; - int ate_index = pcibr_dmamap->bd_ate_index; - bridge_ate_t ate; - - ate = ate_proto | (xio_addr - offset); - ate |= (xio_port << ATE_TIDSHIFT); - - pci_addr = pcibr_dmamap->bd_pci_addr + offset; - - /* Fill in our mapping registers - * with the appropriate xtalk data, - * and hand back the PCI address. - */ - - ASSERT(ate_count > 0); - if (ate_count <= pcibr_dmamap->bd_ate_count) { - ate_write(pcibr_soft, ate_index, ate_count, ate); - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_addr (PMU) : wanted paddr " - "[0x%lx..0x%lx] returning PCI 0x%lx\n", - paddr, paddr + req_size - 1, pci_addr)); - - } else { - /* The number of ATE's required is greater than the number - * allocated for this map. One way this can happen is if - * pcibr_dmamap_alloc() was called with the PCIBR_NO_ATE_ROUNDUP - * flag, and then when that map is used (right now), the - * target address tells us we really did need to roundup. - * The other possibility is that the map is just plain too - * small to handle the requested target area. - */ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_addr (PMU) : wanted paddr " - "[0x%lx..0x%lx] ate_count 0x%x bd_ate_count 0x%x " - "ATE's required > number allocated\n", - paddr, paddr + req_size - 1, - ate_count, pcibr_dmamap->bd_ate_count)); - pci_addr = 0; - } - - } - return pci_addr; -} - -/*ARGSUSED */ -void -pcibr_dmamap_done(pcibr_dmamap_t pcibr_dmamap) -{ - xtalk_dmamap_done(pcibr_dmamap->bd_xtalk); - - PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_dmamap->bd_dev, - "pcibr_dmamap_done: pcibr_dmamap=0x%lx\n", pcibr_dmamap)); -} - - -/* - * For each bridge, the DIR_OFF value in the Direct Mapping Register - * determines the PCI to Crosstalk memory mapping to be used for all - * 32-bit Direct Mapping memory accesses. This mapping can be to any - * node in the system. This function will return that compact node id. - */ - -/*ARGSUSED */ -cnodeid_t -pcibr_get_dmatrans_node(vertex_hdl_t pconn_vhdl) -{ - - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - return nasid_to_cnodeid(NASID_GET(pcibr_soft->bs_dir_xbase)); -} - -/*ARGSUSED */ -iopaddr_t -pcibr_dmatrans_addr(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - paddr_t paddr, - size_t req_size, - unsigned flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[pciio_slot]; - - xwidgetnum_t xio_port; - iopaddr_t xio_addr; - iopaddr_t pci_addr; - - int have_rrbs; - int min_rrbs; - int vchan = VCHAN0; - - /* merge in forced flags */ - flags |= pcibr_soft->bs_dma_flags; - - xio_addr = xtalk_dmatrans_addr(xconn_vhdl, 0, paddr, req_size, - flags & DMAMAP_FLAGS); - if (!xio_addr) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xtalk_dmatrans_addr failed with 0x%lx\n", - paddr, paddr + req_size - 1, xio_addr)); - return 0; - } - /* - * find which XIO port this goes to. - */ - if (XIO_PACKED(xio_addr)) { - if (xio_addr == XIO_NOWHERE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xtalk_dmatrans_addr failed with XIO_NOWHERE\n", - paddr, paddr + req_size - 1)); - return 0; - } - xio_port = XIO_PORT(xio_addr); - xio_addr = XIO_ADDR(xio_addr); - - } else - xio_port = pcibr_soft->bs_mxid; - - /* - * If this DMA comes back to us, - * return the PCI MEM address on - * which it would land, or NULL - * if the target is something - * on bridge other than PCI MEM. - */ - if (xio_port == pcibr_soft->bs_xid) { - pci_addr = pcibr_addr_xio_to_pci(pcibr_soft, xio_addr, req_size); - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, pci_addr=0x%lx\n", - paddr, paddr + req_size - 1, xio_port, pci_addr)); - return pci_addr; - } - /* If the caller can use A64, try to - * satisfy the request with the 64-bit - * direct map. This can fail if the - * configuration bits in Device(x) - * conflict with our flags. - */ - - if (flags & PCIIO_DMA_A64) { - pci_addr = slotp->bss_d64_base; - if (!(flags & PCIBR_VCHAN1)) - flags |= PCIBR_VCHAN0; - if ((pci_addr != PCIBR_D64_BASE_UNSET) && - (flags == slotp->bss_d64_flags)) { - - pci_addr |= xio_addr | - ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, direct64: pci_addr=0x%lx\n", - paddr, paddr + req_size - 1, xio_addr, pci_addr)); - return pci_addr; - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D64_BITS)) { - pci_addr = pcibr_flags_to_d64(flags, pcibr_soft); - slotp->bss_d64_flags = flags; - slotp->bss_d64_base = pci_addr; - pci_addr |= xio_addr - | ((uint64_t) xio_port << PCI64_ATTR_TARG_SHFT); - - /* If in PCI mode, make sure we have an RRB (or two). - */ - if (IS_PCI(pcibr_soft) && - !(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - if (flags & PCIBR_VCHAN1) - vchan = VCHAN1; - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; - if (have_rrbs < 2) { - if (pci_addr & PCI64_ATTR_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - pcibr_rrb_alloc_more(pcibr_soft, pciio_slot, vchan, - min_rrbs - have_rrbs); - } - } - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, direct64: pci_addr=0x%lx, " - "new flags: 0x%x\n", paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags)); - return pci_addr; - } - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, Unable to set direct64 Device(x) bits\n", - paddr, paddr + req_size - 1, xio_addr)); - - /* PIC only supports 64-bit direct mapping in PCI-X mode */ - if (IS_PCIX(pcibr_soft)) { - return 0; - } - - /* our flags conflict with Device(x). try direct32*/ - flags = flags & ~(PCIIO_DMA_A64 | PCIBR_VCHAN0); - } else { - /* BUS in PCI-X mode only supports 64-bit direct mapping */ - if (IS_PCIX(pcibr_soft)) { - return 0; - } - } - /* Try to satisfy the request with the 32-bit direct - * map. This can fail if the configuration bits in - * Device(x) conflict with our flags, or if the - * target address is outside where DIR_OFF points. - */ - { - size_t map_size = 1ULL << 31; - iopaddr_t xio_base = pcibr_soft->bs_dir_xbase; - iopaddr_t offset = xio_addr - xio_base; - iopaddr_t endoff = req_size + offset; - - if ((req_size > map_size) || - (xio_addr < xio_base) || - (xio_port != pcibr_soft->bs_dir_xport) || - (endoff > map_size)) { - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, xio region outside direct32 target\n", - paddr, paddr + req_size - 1, xio_addr)); - } else { - pci_addr = slotp->bss_d32_base; - if ((pci_addr != PCIBR_D32_BASE_UNSET) && - (flags == slotp->bss_d32_flags)) { - - pci_addr |= offset; - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx]," - " xio_port=0x%x, direct32: pci_addr=0x%lx\n", - paddr, paddr + req_size - 1, xio_addr, pci_addr)); - - return pci_addr; - } - if (!pcibr_try_set_device(pcibr_soft, pciio_slot, flags, BRIDGE_DEV_D32_BITS)) { - - pci_addr = PCI32_DIRECT_BASE; - slotp->bss_d32_flags = flags; - slotp->bss_d32_base = pci_addr; - pci_addr |= offset; - - /* Make sure we have an RRB (or two). - */ - if (!(pcibr_soft->bs_rrb_fixed & (1 << pciio_slot))) { - have_rrbs = pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; - if (have_rrbs < 2) { - if (slotp->bss_device & BRIDGE_DEV_PREF) - min_rrbs = 2; - else - min_rrbs = 1; - if (have_rrbs < min_rrbs) - pcibr_rrb_alloc_more(pcibr_soft, pciio_slot, - vchan, min_rrbs - have_rrbs); - } - } - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx]," - " xio_port=0x%x, direct32: pci_addr=0x%lx, " - "new flags: 0x%x\n", paddr, paddr + req_size - 1, - xio_addr, pci_addr, (uint64_t) flags)); - - return pci_addr; - } - /* our flags conflict with Device(x). - */ - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, Unable to set direct32 Device(x) bits\n", - paddr, paddr + req_size - 1, xio_port)); - } - } - - PCIBR_DEBUG((PCIBR_DEBUG_DMADIR, pconn_vhdl, - "pcibr_dmatrans_addr: wanted paddr [0x%lx..0x%lx], " - "xio_port=0x%x, No acceptable PCI address found\n", - paddr, paddr + req_size - 1, xio_port)); - - return 0; -} - -void -pcibr_dmamap_drain(pcibr_dmamap_t map) -{ - xtalk_dmamap_drain(map->bd_xtalk); -} - -void -pcibr_dmaaddr_drain(vertex_hdl_t pconn_vhdl, - paddr_t paddr, - size_t bytes) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - - xtalk_dmaaddr_drain(xconn_vhdl, paddr, bytes); -} - -/* - * Get the starting PCIbus address out of the given DMA map. - * This function is supposed to be used by a close friend of PCI bridge - * since it relies on the fact that the starting address of the map is fixed at - * the allocation time in the current implementation of PCI bridge. - */ -iopaddr_t -pcibr_dmamap_pciaddr_get(pcibr_dmamap_t pcibr_dmamap) -{ - return pcibr_dmamap->bd_pci_addr; -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ -/*ARGSUSED */ -void -pcibr_provider_startup(vertex_hdl_t pcibr) -{ -} - -/*ARGSUSED */ -void -pcibr_provider_shutdown(vertex_hdl_t pcibr) -{ -} - -int -pcibr_reset(vertex_hdl_t conn) -{ - BUG(); - return -1; -} - -pciio_endian_t -pcibr_endian_set(vertex_hdl_t pconn_vhdl, - pciio_endian_t device_end, - pciio_endian_t desired_end) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - uint64_t devreg; - unsigned long s; - - /* - * Bridge supports hardware swapping; so we can always - * arrange for the caller's desired endianness. - */ - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - if (device_end != desired_end) - devreg |= BRIDGE_DEV_SWAP_BITS; - else - devreg &= ~BRIDGE_DEV_SWAP_BITS; - - /* NOTE- if we ever put SWAP bits - * onto the disabled list, we will - * have to change the logic here. - */ - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - pcireg_device_set(pcibr_soft, pciio_slot, devreg); - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - pcireg_tflush_get(pcibr_soft); - } - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl, - "pcibr_endian_set: Device(%d): 0x%x\n", - pciio_slot, devreg)); - - return desired_end; -} - -/* - * Interfaces to allow special (e.g. SGI) drivers to set/clear - * Bridge-specific device flags. Many flags are modified through - * PCI-generic interfaces; we don't allow them to be directly - * manipulated here. Only flags that at this point seem pretty - * Bridge-specific can be set through these special interfaces. - * We may add more flags as the need arises, or remove flags and - * create PCI-generic interfaces as the need arises. - * - * Returns 0 on failure, 1 on success - */ -int -pcibr_device_flags_set(vertex_hdl_t pconn_vhdl, - pcibr_device_flags_t flags) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - uint64_t set = 0; - uint64_t clr = 0; - - ASSERT((flags & PCIBR_DEVICE_FLAGS) == flags); - - if (flags & PCIBR_WRITE_GATHER) - set |= BRIDGE_DEV_PMU_WRGA_EN; - if (flags & PCIBR_NOWRITE_GATHER) - clr |= BRIDGE_DEV_PMU_WRGA_EN; - - if (flags & PCIBR_PREFETCH) - set |= BRIDGE_DEV_PREF; - if (flags & PCIBR_NOPREFETCH) - clr |= BRIDGE_DEV_PREF; - - if (flags & PCIBR_PRECISE) - set |= BRIDGE_DEV_PRECISE; - if (flags & PCIBR_NOPRECISE) - clr |= BRIDGE_DEV_PRECISE; - - if (flags & PCIBR_BARRIER) - set |= BRIDGE_DEV_BARRIER; - if (flags & PCIBR_NOBARRIER) - clr |= BRIDGE_DEV_BARRIER; - - if (flags & PCIBR_64BIT) - set |= BRIDGE_DEV_DEV_SIZE; - if (flags & PCIBR_NO64BIT) - clr |= BRIDGE_DEV_DEV_SIZE; - - /* PIC BRINGUP WAR (PV# 878674): Don't allow 64bit PIO accesses */ - if ((flags & PCIBR_64BIT) && PCIBR_WAR_ENABLED(PV878674, pcibr_soft)) { - set &= ~BRIDGE_DEV_DEV_SIZE; - } - - if (set || clr) { - uint64_t devreg; - unsigned long s; - - s = pcibr_lock(pcibr_soft); - devreg = pcibr_soft->bs_slot[pciio_slot].bss_device; - devreg = (devreg & ~clr) | set; - if (pcibr_soft->bs_slot[pciio_slot].bss_device != devreg) { - pcireg_device_set(pcibr_soft, pciio_slot, devreg); - pcibr_soft->bs_slot[pciio_slot].bss_device = devreg; - pcireg_tflush_get(pcibr_soft); - } - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pconn_vhdl, - "pcibr_device_flags_set: Device(%d): 0x%x\n", - pciio_slot, devreg)); - } - return 1; -} - -/* - * PIC has 16 RBARs per bus; meaning it can have a total of 16 outstanding - * split transactions. If the functions on the bus have requested a total - * of 16 or less, then we can give them what they requested (ie. 100%). - * Otherwise we have make sure each function can get at least one buffer - * and then divide the rest of the buffers up among the functions as ``A - * PERCENTAGE OF WHAT THEY REQUESTED'' (i.e. 0% - 100% of a function's - * pcix_type0_status.max_out_split). This percentage does not include the - * one RBAR that all functions get by default. - */ -int -pcibr_pcix_rbars_calc(pcibr_soft_t pcibr_soft) -{ - /* 'percent_allowed' is the percentage of requested RBARs that functions - * are allowed, ***less the 1 RBAR that all functions get by default*** - */ - int percent_allowed; - - if (pcibr_soft->bs_pcix_num_funcs) { - if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) { - printk(KERN_WARNING - "%s: Must oversubscribe Read Buffer Attribute Registers" - "(RBAR). Bus has %d RBARs but %d funcs need them.\n", - pcibr_soft->bs_name, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs); - percent_allowed = 0; - } else { - percent_allowed = (((NUM_RBAR-pcibr_soft->bs_pcix_num_funcs)*100) / - pcibr_soft->bs_pcix_split_tot); - - /* +1 to percentage to solve rounding errors that occur because - * we're not doing fractional math. (ie. ((3 * 66%) / 100) = 1) - * but should be "2" if doing true fractional math. NOTE: Since - * the greatest number of outstanding transactions a function - * can request is 32, this "+1" will always work (i.e. we won't - * accidentally oversubscribe the RBARs because of this rounding - * of the percentage). - */ - percent_allowed=(percent_allowed > 100) ? 100 : percent_allowed+1; - } - } else { - return -ENODEV; - } - - return percent_allowed; -} - -/* - * pcibr_debug() is used to print pcibr debug messages to the console. A - * user enables tracing by setting the following global variables: - * - * pcibr_debug_mask -Bitmask of what to trace. see pcibr_private.h - * pcibr_debug_module -Module to trace. 'all' means trace all modules - * pcibr_debug_widget -Widget to trace. '-1' means trace all widgets - * pcibr_debug_slot -Slot to trace. '-1' means trace all slots - * - * 'type' is the type of debugging that the current PCIBR_DEBUG macro is - * tracing. 'vhdl' (which can be NULL) is the vhdl associated with the - * debug statement. If there is a 'vhdl' associated with this debug - * statement, it is parsed to obtain the module, widget, and slot. If the - * globals above match the PCIBR_DEBUG params, then the debug info in the - * parameter 'format' is sent to the console. - */ -void -pcibr_debug(uint32_t type, vertex_hdl_t vhdl, char *format, ...) -{ - char hwpath[MAXDEVNAME] = "\0"; - char copy_of_hwpath[MAXDEVNAME]; - char *buffer; - char *module = "all"; - short widget = -1; - short slot = -1; - va_list ap; - - if (pcibr_debug_mask & type) { - if (vhdl) { - if (!hwgraph_vertex_name_get(vhdl, hwpath, MAXDEVNAME)) { - char *cp; - - if (strcmp(module, pcibr_debug_module)) { - /* use a copy */ - (void)strcpy(copy_of_hwpath, hwpath); - cp = strstr(copy_of_hwpath, "/" EDGE_LBL_MODULE "/"); - if (cp) { - cp += strlen("/" EDGE_LBL_MODULE "/"); - module = strsep(&cp, "/"); - } - } - if (pcibr_debug_widget != -1) { - cp = strstr(hwpath, "/" EDGE_LBL_XTALK "/"); - if (cp) { - cp += strlen("/" EDGE_LBL_XTALK "/"); - widget = simple_strtoul(cp, NULL, 0); - } - } - if (pcibr_debug_slot != -1) { - cp = strstr(hwpath, "/" EDGE_LBL_PCIX_0 "/"); - if (!cp) { - cp = strstr(hwpath, "/" EDGE_LBL_PCIX_1 "/"); - } - if (cp) { - cp += strlen("/" EDGE_LBL_PCIX_0 "/"); - slot = simple_strtoul(cp, NULL, 0); - } - } - } - } - if ((vhdl == NULL) || - (!strcmp(module, pcibr_debug_module) && - (widget == pcibr_debug_widget) && - (slot == pcibr_debug_slot))) { - - buffer = kmalloc(1024, GFP_KERNEL); - if (buffer) { - printk("PCIBR_DEBUG<%d>\t: %s :", smp_processor_id(), hwpath); - /* - * KERN_MSG translates to this 3 line sequence. Since - * we have a variable length argument list, we need to - * call KERN_MSG this way rather than directly - */ - va_start(ap, format); - memset(buffer, 0, 1024); - vsnprintf(buffer, 1024, format, ap); - va_end(ap); - printk("%s", buffer); - kfree(buffer); - } - } - } -} - -/* - * given a xconn_vhdl and a bus number under that widget, return a - * bridge_t pointer. - */ -void * -pcibr_bridge_ptr_get(vertex_hdl_t widget_vhdl, int bus_num) -{ - void *bridge; - - bridge = (void *)xtalk_piotrans_addr(widget_vhdl, 0, 0, - sizeof(bridge), 0); - - /* PIC ASIC has two bridges (ie. two buses) under a single widget */ - if (bus_num == 1) { - bridge = (void *)((char *)bridge + PIC_BUS1_OFFSET); - } - return bridge; -} - - -int -isIO9(nasid_t nasid) -{ - lboard_t *brd = (lboard_t *)KL_CONFIG_INFO(nasid); - - while (brd) { - if (brd->brd_flags & LOCAL_MASTER_IO6) { - return 1; - } - if (numionodes == numnodes) - brd = KLCF_NEXT_ANY(brd); - else - brd = KLCF_NEXT(brd); - } - /* if it's dual ported, check the peer also */ - nasid = NODEPDA(nasid_to_cnodeid(nasid))->xbow_peer; - if (nasid < 0) return 0; - brd = (lboard_t *)KL_CONFIG_INFO(nasid); - while (brd) { - if (brd->brd_flags & LOCAL_MASTER_IO6) { - return 1; - } - if (numionodes == numnodes) - brd = KLCF_NEXT_ANY(brd); - else - brd = KLCF_NEXT(brd); - - } - return 0; -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c deleted file mode 100644 index 64d27f883..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_error.c +++ /dev/null @@ -1,1873 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -extern int hubii_check_widget_disabled(nasid_t, int); - - -/* ===================================================================== - * ERROR HANDLING - */ - -#ifdef DEBUG -#ifdef ERROR_DEBUG -#define BRIDGE_PIOERR_TIMEOUT 100 /* Timeout with ERROR_DEBUG defined */ -#else -#define BRIDGE_PIOERR_TIMEOUT 40 /* Timeout in debug mode */ -#endif -#else -#define BRIDGE_PIOERR_TIMEOUT 1 /* Timeout in non-debug mode */ -#endif - -#ifdef DEBUG -#ifdef ERROR_DEBUG -uint64_t bridge_errors_to_dump = ~BRIDGE_ISR_INT_MSK; -#else -uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_DUMP; -#endif -#else -uint64_t bridge_errors_to_dump = BRIDGE_ISR_ERROR_FATAL | - BRIDGE_ISR_PCIBUS_PIOERR; -#endif - -int pcibr_pioerr_dump = 1; /* always dump pio errors */ - -/* - * register values - * map between numeric values and symbolic values - */ -struct reg_values { - unsigned long long rv_value; - char *rv_name; -}; - -/* - * register descriptors are used for formatted prints of register values - * rd_mask and rd_shift must be defined, other entries may be null - */ -struct reg_desc { - unsigned long long rd_mask; /* mask to extract field */ - int rd_shift; /* shift for extracted value, - >>, + << */ - char *rd_name; /* field name */ - char *rd_format; /* format to print field */ - struct reg_values *rd_values; /* symbolic names of values */ -}; - -/* Crosstalk Packet Types */ -static struct reg_values xtalk_cmd_pactyp[] = -{ - {0x0, "RdReq"}, - {0x1, "RdResp"}, - {0x2, "WrReqWithResp"}, - {0x3, "WrResp"}, - {0x4, "WrReqNoResp"}, - {0x5, "Reserved(5)"}, - {0x6, "FetchAndOp"}, - {0x7, "Reserved(7)"}, - {0x8, "StoreAndOp"}, - {0x9, "Reserved(9)"}, - {0xa, "Reserved(a)"}, - {0xb, "Reserved(b)"}, - {0xc, "Reserved(c)"}, - {0xd, "Reserved(d)"}, - {0xe, "SpecialReq"}, - {0xf, "SpecialResp"}, - {0} -}; - -static struct reg_desc xtalk_cmd_bits[] = -{ - {WIDGET_DIDN, -28, "DIDN", "%x"}, - {WIDGET_SIDN, -24, "SIDN", "%x"}, - {WIDGET_PACTYP, -20, "PACTYP", 0, xtalk_cmd_pactyp}, - {WIDGET_TNUM, -15, "TNUM", "%x"}, - {WIDGET_COHERENT, 0, "COHERENT"}, - {WIDGET_DS, 0, "DS"}, - {WIDGET_GBR, 0, "GBR"}, - {WIDGET_VBPM, 0, "VBPM"}, - {WIDGET_ERROR, 0, "ERROR"}, - {WIDGET_BARRIER, 0, "BARRIER"}, - {0} -}; - -#define F(s,n) { 1l<<(s),-(s), n } - -char *pci_space[] = {"NONE", - "ROM", - "IO", - "", - "MEM", - "MEM32", - "MEM64", - "CFG", - "WIN0", - "WIN1", - "WIN2", - "WIN3", - "WIN4", - "WIN5", - "", - "BAD"}; - -static char *pcibr_isr_errs[] = -{ - "", "", "", "", "", "", "", "", - "08: Reserved Bit 08", - "09: PCI to Crosstalk read request timeout", - "10: PCI retry operation count exhausted.", - "11: PCI bus device select timeout", - "12: PCI device reported parity error", - "13: PCI Address/Cmd parity error ", - "14: PCI Bridge detected parity error", - "15: PCI abort condition", - "16: Reserved Bit 16", - "17: LLP Transmitter Retry count wrapped", /* PIC ONLY */ - "18: LLP Transmitter side required Retry", /* PIC ONLY */ - "19: LLP Receiver retry count wrapped", /* PIC ONLY */ - "20: LLP Receiver check bit error", /* PIC ONLY */ - "21: LLP Receiver sequence number error", /* PIC ONLY */ - "22: Request packet overflow", - "23: Request operation not supported by bridge", - "24: Request packet has invalid address for bridge widget", - "25: Incoming request xtalk command word error bit set or invalid sideband", - "26: Incoming response xtalk command word error bit set or invalid sideband", - "27: Framing error, request cmd data size does not match actual", - "28: Framing error, response cmd data size does not match actual", - "29: Unexpected response arrived", - "30: PMU Access Fault", - "31: Reserved Bit 31", - "32: PCI-X address or attribute cycle parity error", - "33: PCI-X data cycle parity error", - "34: PCI-X master timeout (ie. master abort)", - "35: PCI-X pio retry counter exhausted", - "36: PCI-X SERR", - "37: PCI-X PERR", - "38: PCI-X target abort", - "39: PCI-X read request timeout", - "40: PCI / PCI-X device requestin arbitration error", - "41: internal RAM parity error", - "42: PCI-X unexpected completion cycle to master", - "43: PCI-X split completion timeout", - "44: PCI-X split completion error message", - "45: PCI-X split completion message parity error", -}; - -/* - * print_register() allows formatted printing of bit fields. individual - * bit fields are described by a struct reg_desc, multiple bit fields within - * a single word can be described by multiple reg_desc structures. - * %r outputs a string of the format "" - * %R outputs a string of the format "0x%x" - * - * The fields in a reg_desc are: - * unsigned long long rd_mask; An appropriate mask to isolate the bit field - * within a word, and'ed with val - * - * int rd_shift; A shift amount to be done to the isolated - * bit field. done before printing the isolate - * bit field with rd_format and before searching - * for symbolic value names in rd_values - * - * char *rd_name; If non-null, a bit field name to label any - * out from rd_format or searching rd_values. - * if neither rd_format or rd_values is non-null - * rd_name is printed only if the isolated - * bit field is non-null. - * - * char *rd_format; If non-null, the shifted bit field value - * is printed using this format. - * - * struct reg_values *rd_values; If non-null, a pointer to a table - * matching numeric values with symbolic names. - * rd_values are searched and the symbolic - * value is printed if a match is found, if no - * match is found "???" is printed. - * - */ - -static void -print_register(unsigned long long reg, struct reg_desc *addr) -{ - register struct reg_desc *rd; - register struct reg_values *rv; - unsigned long long field; - int any; - - printk("<"); - any = 0; - for (rd = addr; rd->rd_mask; rd++) { - field = reg & rd->rd_mask; - field = (rd->rd_shift > 0) ? field << rd->rd_shift : field >> -rd->rd_shift; - if (any && (rd->rd_format || rd->rd_values || (rd->rd_name && field))) - printk(","); - if (rd->rd_name) { - if (rd->rd_format || rd->rd_values || field) { - printk("%s", rd->rd_name); - any = 1; - } - if (rd->rd_format || rd->rd_values) { - printk("="); - any = 1; - } - } - /* You can have any format so long as it is %x */ - if (rd->rd_format) { - printk("%llx", field); - any = 1; - if (rd->rd_values) - printk(":"); - } - if (rd->rd_values) { - any = 1; - for (rv = rd->rd_values; rv->rv_name; rv++) { - if (field == rv->rv_value) { - printk("%s", rv->rv_name); - break; - } - } - if (rv->rv_name == NULL) - printk("???"); - } - } - printk(">\n"); -} - - -/* - * display memory directory state - */ -static void -pcibr_show_dir_state(paddr_t paddr, char *prefix) -{ -#ifdef PCIBR_LATER - int state; - uint64_t vec_ptr; - hubreg_t elo; - extern char *dir_state_str[]; - extern void get_dir_ent(paddr_t, int *, uint64_t *, hubreg_t *); - - get_dir_ent(paddr, &state, &vec_ptr, &elo); - - printf("%saddr 0x%lx: state 0x%x owner 0x%lx (%s)\n", - prefix, (uint64_t)paddr, state, (uint64_t)vec_ptr, - dir_state_str[state]); -#endif /* PCIBR_LATER */ -} - - -void -print_bridge_errcmd(pcibr_soft_t pcibr_soft, uint32_t cmdword, char *errtype) -{ - printk( - "\t Bridge %sError Command Word Register ", errtype); - print_register(cmdword, xtalk_cmd_bits); -} - - -/* - * Dump relevant error information for Bridge error interrupts. - */ -/*ARGSUSED */ -void -pcibr_error_dump(pcibr_soft_t pcibr_soft) -{ - uint64_t int_status; - uint64_t mult_int; - uint64_t bit; - int i; - - int_status = (pcireg_intr_status_get(pcibr_soft) & ~BRIDGE_ISR_INT_MSK); - - if (!int_status) { - /* No error bits set */ - return; - } - - /* Check if dumping the same error information multiple times */ - if ( pcibr_soft->bs_errinfo.bserr_intstat == int_status ) - return; - pcibr_soft->bs_errinfo.bserr_intstat = int_status; - - printk(KERN_ALERT "PCI BRIDGE ERROR: int_status is 0x%lx for %s\n" - " Dumping relevant %s registers for each bit set...\n", - int_status, pcibr_soft->bs_name, - "PIC"); - - for (i = PCIBR_ISR_ERR_START; i < 64; i++) { - bit = 1ull << i; - - /* A number of int_status bits are only valid for PIC's bus0 */ - if ((pcibr_soft->bs_busnum != 0) && - ((bit == BRIDGE_ISR_UNSUPPORTED_XOP) || - (bit == BRIDGE_ISR_LLP_REC_SNERR) || - (bit == BRIDGE_ISR_LLP_REC_CBERR) || - (bit == BRIDGE_ISR_LLP_RCTY) || - (bit == BRIDGE_ISR_LLP_TX_RETRY) || - (bit == BRIDGE_ISR_LLP_TCTY))) { - continue; - } - - if (int_status & bit) { - printk("\t%s\n", pcibr_isr_errs[i]); - - switch (bit) { - - case PIC_ISR_INT_RAM_PERR: /* bit41 INT_RAM_PERR */ - /* XXX: should breakdown meaning of bits in reg */ - printk("\t Internal RAM Parity Error: 0x%lx\n", - pcireg_parity_err_get(pcibr_soft)); - break; - - case PIC_ISR_PCIX_ARB_ERR: /* bit40 PCI_X_ARB_ERR */ - /* XXX: should breakdown meaning of bits in reg */ - printk("\t Arbitration Reg: 0x%lx\n", - pcireg_arbitration_get(pcibr_soft)); - break; - - case PIC_ISR_PCIX_REQ_TOUT: /* bit39 PCI_X_REQ_TOUT */ - /* XXX: should breakdown meaning of attribute bit */ - printk( - "\t PCI-X DMA Request Error Address Reg: 0x%lx\n" - "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", - pcireg_pcix_req_err_addr_get(pcibr_soft), - pcireg_pcix_req_err_attr_get(pcibr_soft)); - break; - - case PIC_ISR_PCIX_SPLIT_MSG_PE: /* bit45 PCI_X_SPLIT_MES_PE */ - case PIC_ISR_PCIX_SPLIT_EMSG: /* bit44 PCI_X_SPLIT_EMESS */ - case PIC_ISR_PCIX_SPLIT_TO: /* bit43 PCI_X_SPLIT_TO */ - /* XXX: should breakdown meaning of attribute bit */ - printk( - "\t PCI-X Split Request Address Reg: 0x%lx\n" - "\t PCI-X Split Request Attribute Reg: 0x%lx\n", - pcireg_pcix_pio_split_addr_get(pcibr_soft), - pcireg_pcix_pio_split_attr_get(pcibr_soft)); - /* FALL THRU */ - - case PIC_ISR_PCIX_UNEX_COMP: /* bit42 PCI_X_UNEX_COMP */ - case PIC_ISR_PCIX_TABORT: /* bit38 PCI_X_TABORT */ - case PIC_ISR_PCIX_PERR: /* bit37 PCI_X_PERR */ - case PIC_ISR_PCIX_SERR: /* bit36 PCI_X_SERR */ - case PIC_ISR_PCIX_MRETRY: /* bit35 PCI_X_MRETRY */ - case PIC_ISR_PCIX_MTOUT: /* bit34 PCI_X_MTOUT */ - case PIC_ISR_PCIX_DA_PARITY: /* bit33 PCI_X_DA_PARITY */ - case PIC_ISR_PCIX_AD_PARITY: /* bit32 PCI_X_AD_PARITY */ - /* XXX: should breakdown meaning of attribute bit */ - printk( - "\t PCI-X Bus Error Address Reg: 0x%lx\n" - "\t PCI-X Bus Error Attribute Reg: 0x%lx\n" - "\t PCI-X Bus Error Data Reg: 0x%lx\n", - pcireg_pcix_bus_err_addr_get(pcibr_soft), - pcireg_pcix_bus_err_attr_get(pcibr_soft), - pcireg_pcix_bus_err_data_get(pcibr_soft)); - break; - - case BRIDGE_ISR_PAGE_FAULT: /* bit30 PMU_PAGE_FAULT */ - printk("\t Map Fault Address Reg: 0x%lx\n", - pcireg_map_fault_get(pcibr_soft)); - break; - - case BRIDGE_ISR_UNEXP_RESP: /* bit29 UNEXPECTED_RESP */ - print_bridge_errcmd(pcibr_soft, - pcireg_linkside_err_get(pcibr_soft), "Aux "); - - /* PIC in PCI-X mode, dump the PCIX DMA Request registers */ - if (IS_PCIX(pcibr_soft)) { - /* XXX: should breakdown meaning of attr bit */ - printk( - "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" - "\t PCI-X DMA Request Error Attr Reg: 0x%lx\n", - pcireg_pcix_req_err_addr_get(pcibr_soft), - pcireg_pcix_req_err_attr_get(pcibr_soft)); - } - break; - - case BRIDGE_ISR_BAD_XRESP_PKT: /* bit28 BAD_RESP_PACKET */ - case BRIDGE_ISR_RESP_XTLK_ERR: /* bit26 RESP_XTALK_ERROR */ - print_bridge_errcmd(pcibr_soft, - pcireg_linkside_err_get(pcibr_soft), "Aux "); - - /* PCI-X mode, DMA Request Error registers are valid. But - * in PCI mode, Response Buffer Address register are valid. - */ - if (IS_PCIX(pcibr_soft)) { - /* XXX: should breakdown meaning of attribute bit */ - printk( - "\t PCI-X DMA Request Error Addr Reg: 0x%lx\n" - "\t PCI-X DMA Request Error Attribute Reg: 0x%lx\n", - pcireg_pcix_req_err_addr_get(pcibr_soft), - pcireg_pcix_req_err_attr_get(pcibr_soft)); - } else { - printk( - "\t Bridge Response Buf Error Addr Reg: 0x%lx\n" - "\t dev-num %d buff-num %d addr 0x%lx\n", - pcireg_resp_err_get(pcibr_soft), - (int)pcireg_resp_err_dev_get(pcibr_soft), - (int)pcireg_resp_err_buf_get(pcibr_soft), - pcireg_resp_err_addr_get(pcibr_soft)); - if (bit == BRIDGE_ISR_RESP_XTLK_ERR) { - /* display memory directory associated with cacheline */ - pcibr_show_dir_state( - pcireg_resp_err_get(pcibr_soft), "\t "); - } - } - break; - - case BRIDGE_ISR_BAD_XREQ_PKT: /* bit27 BAD_XREQ_PACKET */ - case BRIDGE_ISR_REQ_XTLK_ERR: /* bit25 REQ_XTALK_ERROR */ - case BRIDGE_ISR_INVLD_ADDR: /* bit24 INVALID_ADDRESS */ - print_bridge_errcmd(pcibr_soft, - pcireg_cmdword_err_get(pcibr_soft), ""); - printk( - "\t Bridge Error Address Register: 0x%lx\n" - "\t Bridge Error Address: 0x%lx\n", - pcireg_bus_err_get(pcibr_soft), - pcireg_bus_err_get(pcibr_soft)); - break; - - case BRIDGE_ISR_UNSUPPORTED_XOP: /* bit23 UNSUPPORTED_XOP */ - print_bridge_errcmd(pcibr_soft, - pcireg_linkside_err_get(pcibr_soft), "Aux "); - printk("\t Address Holding Link Side Error Reg: 0x%lx\n", - pcireg_linkside_err_addr_get(pcibr_soft)); - break; - - case BRIDGE_ISR_XREQ_FIFO_OFLOW: /* bit22 XREQ_FIFO_OFLOW */ - print_bridge_errcmd(pcibr_soft, - pcireg_linkside_err_get(pcibr_soft), "Aux "); - printk("\t Address Holding Link Side Error Reg: 0x%lx\n", - pcireg_linkside_err_addr_get(pcibr_soft)); - break; - - case BRIDGE_ISR_PCI_ABORT: /* bit15 PCI_ABORT */ - case BRIDGE_ISR_PCI_PARITY: /* bit14 PCI_PARITY */ - case BRIDGE_ISR_PCI_SERR: /* bit13 PCI_SERR */ - case BRIDGE_ISR_PCI_PERR: /* bit12 PCI_PERR */ - case BRIDGE_ISR_PCI_MST_TIMEOUT: /* bit11 PCI_MASTER_TOUT */ - case BRIDGE_ISR_PCI_RETRY_CNT: /* bit10 PCI_RETRY_CNT */ - printk("\t PCI Error Address Register: 0x%lx\n" - "\t PCI Error Address: 0x%lx\n", - pcireg_pci_bus_addr_get(pcibr_soft), - pcireg_pci_bus_addr_addr_get(pcibr_soft)); - break; - - case BRIDGE_ISR_XREAD_REQ_TIMEOUT: /* bit09 XREAD_REQ_TOUT */ - printk("\t Bridge Response Buf Error Addr Reg: 0x%lx\n" - "\t dev-num %d buff-num %d addr 0x%lx\n", - pcireg_resp_err_get(pcibr_soft), - (int)pcireg_resp_err_dev_get(pcibr_soft), - (int)pcireg_resp_err_buf_get(pcibr_soft), - pcireg_resp_err_get(pcibr_soft)); - break; - } - } - } - - mult_int = pcireg_intr_multiple_get(pcibr_soft); - - if (mult_int & ~BRIDGE_ISR_INT_MSK) { - printk(" %s Multiple Interrupt Register is 0x%lx\n", - pcibr_soft->bs_asic_name, mult_int); - for (i = PCIBR_ISR_ERR_START; i < 64; i++) { - if (mult_int & (1ull << i)) - printk( "\t%s\n", pcibr_isr_errs[i]); - } - } -} - -/* pcibr_pioerr_check(): - * Check to see if this pcibr has a PCI PIO - * TIMEOUT error; if so, bump the timeout-count - * on any piomaps that could cover the address. - */ -static void -pcibr_pioerr_check(pcibr_soft_t soft) -{ - uint64_t int_status; - iopaddr_t pci_addr; - pciio_slot_t slot; - pcibr_piomap_t map; - iopaddr_t base; - size_t size; - unsigned win; - int func; - - int_status = pcireg_intr_status_get(soft); - - if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - pci_addr = pcireg_pci_bus_addr_get(soft); - - slot = PCIBR_NUM_SLOTS(soft); - while (slot-- > 0) { - int nfunc = soft->bs_slot[slot].bss_ninfo; - pcibr_info_h pcibr_infoh = soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; func++) { - pcibr_info_t pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - for (map = pcibr_info->f_piomap; - map != NULL; map = map->bp_next) { - base = map->bp_pciaddr; - size = map->bp_mapsz; - win = map->bp_space - PCIIO_SPACE_WIN(0); - if (win < 6) - base += soft->bs_slot[slot].bss_window[win].bssw_base; - else if (map->bp_space == PCIIO_SPACE_ROM) - base += pcibr_info->f_rbase; - if ((pci_addr >= base) && (pci_addr < (base + size))) - atomic_inc(&map->bp_toc); - } - } - } - } -} - -/* - * PCI Bridge Error interrupt handler. - * This gets invoked, whenever a PCI bridge sends an error interrupt. - * Primarily this servers two purposes. - * - If an error can be handled (typically a PIO read/write - * error, we try to do it silently. - * - If an error cannot be handled, we die violently. - * Interrupt due to PIO errors: - * - Bridge sends an interrupt, whenever a PCI operation - * done by the bridge as the master fails. Operations could - * be either a PIO read or a PIO write. - * PIO Read operation also triggers a bus error, and it's - * We primarily ignore this interrupt in that context.. - * For PIO write errors, this is the only indication. - * and we have to handle with the info from here. - * - * So, there is no way to distinguish if an interrupt is - * due to read or write error!. - */ - -irqreturn_t -pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *ep) -{ - pcibr_soft_t pcibr_soft; - void *bridge; - uint64_t int_status; - uint64_t err_status; - int i; - uint64_t disable_errintr_mask = 0; - nasid_t nasid; - - -#if PCIBR_SOFT_LIST - /* - * Defensive code for linked pcibr_soft structs - */ - { - extern pcibr_list_p pcibr_list; - pcibr_list_p entry; - - entry = pcibr_list; - while (1) { - if (entry == NULL) { - printk("pcibr_error_intr_handler: (0x%lx) is not a pcibr_soft!", - (uint64_t)arg); - return IRQ_NONE; - } - if ((intr_arg_t) entry->bl_soft == arg) - break; - entry = entry->bl_next; - } - } -#endif /* PCIBR_SOFT_LIST */ - pcibr_soft = (pcibr_soft_t) arg; - bridge = pcibr_soft->bs_base; - - /* - * pcibr_error_intr_handler gets invoked whenever bridge encounters - * an error situation, and the interrupt for that error is enabled. - * This routine decides if the error is fatal or not, and takes - * action accordingly. - * - * In the case of PIO read/write timeouts, there is no way - * to know if it was a read or write request that timed out. - * If the error was due to a "read", a bus error will also occur - * and the bus error handling code takes care of it. - * If the error is due to a "write", the error is currently logged - * by this routine. For SN1 and SN0, if fire-and-forget mode is - * disabled, a write error response xtalk packet will be sent to - * the II, which will cause an II error interrupt. No write error - * recovery actions of any kind currently take place at the pcibr - * layer! (e.g., no panic on unrecovered write error) - * - * Prior to reading the Bridge int_status register we need to ensure - * that there are no error bits set in the lower layers (hubii) - * that have disabled PIO access to the widget. If so, there is nothing - * we can do until the bits clear, so we setup a timeout and try again - * later. - */ - - nasid = NASID_GET(bridge); - if (hubii_check_widget_disabled(nasid, pcibr_soft->bs_xid)) { - DECLARE_WAIT_QUEUE_HEAD(wq); - sleep_on_timeout(&wq, BRIDGE_PIOERR_TIMEOUT*HZ ); /* sleep */ - pcibr_soft->bs_errinfo.bserr_toutcnt++; - /* Let's go recursive */ - return(pcibr_error_intr_handler(irq, arg, ep)); - } - - int_status = pcireg_intr_status_get(pcibr_soft); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn, - "pcibr_error_intr_handler: int_status=0x%lx\n", int_status)); - - /* int_status is which bits we have to clear; - * err_status is the bits we haven't handled yet. - */ - err_status = int_status; - - if (!(int_status & ~BRIDGE_ISR_INT_MSK)) { - /* - * No error bit set!!. - */ - return IRQ_HANDLED; - } - /* - * If we have a PCIBUS_PIOERR, hand it to the logger. - */ - if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) { - pcibr_pioerr_check(pcibr_soft); - } - - if (err_status) { - struct bs_errintr_stat_s *bs_estat ; - bs_estat = &pcibr_soft->bs_errintr_stat[PCIBR_ISR_ERR_START]; - - for (i = PCIBR_ISR_ERR_START; i < 64; i++, bs_estat++) { - if (err_status & (1ull << i)) { - uint32_t errrate = 0; - uint32_t errcount = 0; - uint32_t errinterval = 0, current_tick = 0; - int llp_tx_retry_errors = 0; - int is_llp_tx_retry_intr = 0; - - bs_estat->bs_errcount_total++; - - current_tick = jiffies; - errinterval = (current_tick - bs_estat->bs_lasterr_timestamp); - errcount = (bs_estat->bs_errcount_total - - bs_estat->bs_lasterr_snapshot); - - /* LLP interrrupt errors are only valid on BUS0 of the PIC */ - if (pcibr_soft->bs_busnum == 0) - is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY==(1ull << i)); - - /* Check for the divide by zero condition while - * calculating the error rates. - */ - - if (errinterval) { - errrate = errcount / errinterval; - /* If able to calculate error rate - * on a LLP transmitter retry interrupt, check - * if the error rate is nonzero and we have seen - * a certain minimum number of errors. - * - * NOTE : errcount is being compared to - * PCIBR_ERRTIME_THRESHOLD to make sure that we are not - * seeing cases like x error interrupts per y ticks for - * very low x ,y (x > y ) which could result in a - * rate > 100/tick. - */ - if (is_llp_tx_retry_intr && - errrate && - (errcount >= PCIBR_ERRTIME_THRESHOLD)) { - llp_tx_retry_errors = 1; - } - } else { - errrate = 0; - /* Since we are not able to calculate the - * error rate check if we exceeded a certain - * minimum number of errors for LLP transmitter - * retries. Note that this can only happen - * within the first tick after the last snapshot. - */ - if (is_llp_tx_retry_intr && - (errcount >= PCIBR_ERRINTR_DISABLE_LEVEL)) { - llp_tx_retry_errors = 1; - } - } - - /* - * If a non-zero error rate (which is equivalent to - * to 100 errors/tick at least) for the LLP transmitter - * retry interrupt was seen, check if we should print - * a warning message. - */ - - if (llp_tx_retry_errors) { - static uint32_t last_printed_rate; - - if (errrate > last_printed_rate) { - last_printed_rate = errrate; - /* Print the warning only if the error rate - * for the transmitter retry interrupt - * exceeded the previously printed rate. - */ - printk(KERN_WARNING - "%s: %s, Excessive error interrupts : %d/tick\n", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - errrate); - - } - /* - * Update snapshot, and time - */ - bs_estat->bs_lasterr_timestamp = current_tick; - bs_estat->bs_lasterr_snapshot = - bs_estat->bs_errcount_total; - - } - /* - * If the error rate is high enough, print the error rate. - */ - if (errinterval > PCIBR_ERRTIME_THRESHOLD) { - - if (errrate > PCIBR_ERRRATE_THRESHOLD) { - printk(KERN_NOTICE "%s: %s, Error rate %d/tick", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - errrate); - /* - * Update snapshot, and time - */ - bs_estat->bs_lasterr_timestamp = current_tick; - bs_estat->bs_lasterr_snapshot = - bs_estat->bs_errcount_total; - } - } - /* PIC BRINGUP WAR (PV# 856155): - * Dont disable PCI_X_ARB_ERR interrupts, we need the - * interrupt inorder to clear the DEV_BROKE bits in - * b_arb register to re-enable the device. - */ - if (!(err_status & PIC_ISR_PCIX_ARB_ERR) && - PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) { - - if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) { - /* - * We have seen a fairly large number of errors of - * this type. Let's disable the interrupt. But flash - * a message about the interrupt being disabled. - */ - printk(KERN_NOTICE - "%s Disabling error interrupt type %s. Error count %d", - pcibr_soft->bs_name, - pcibr_isr_errs[i], - bs_estat->bs_errcount_total); - disable_errintr_mask |= (1ull << i); - } - } /* PIC: WAR for PV 856155 end-of-if */ - } - } - } - - if (disable_errintr_mask) { - unsigned long s; - /* - * Disable some high frequency errors as they - * could eat up too much cpu time. - */ - s = pcibr_lock(pcibr_soft); - pcireg_intr_enable_bit_clr(pcibr_soft, disable_errintr_mask); - pcibr_unlock(pcibr_soft, s); - } - /* - * If we leave the PROM cacheable, T5 might - * try to do a cache line sized writeback to it, - * which will cause a BRIDGE_ISR_INVLD_ADDR. - */ - if ((err_status & BRIDGE_ISR_INVLD_ADDR) && - (0x00C00000 == (pcireg_bus_err_get(pcibr_soft) & 0xFFFFFFFFFFC00000)) && - (0x00402000 == (0x00F07F00 & pcireg_cmdword_err_get(pcibr_soft)))) { - err_status &= ~BRIDGE_ISR_INVLD_ADDR; - } - /* - * pcibr_pioerr_dump is a systune that make be used to not - * print bridge registers for interrupts generated by pio-errors. - * Some customers do early probes and expect a lot of failed - * pios. - */ - if (!pcibr_pioerr_dump) { - bridge_errors_to_dump &= ~BRIDGE_ISR_PCIBUS_PIOERR; - } else { - bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR; - } - - /* Dump/Log Bridge error interrupt info */ - if (err_status & bridge_errors_to_dump) { - printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); - pcibr_error_dump(pcibr_soft); - } - - /* PIC BRINGUP WAR (PV# 867308): - * Make BRIDGE_ISR_LLP_REC_SNERR & BRIDGE_ISR_LLP_REC_CBERR fatal errors - * so we know we've hit the problem defined in PV 867308 that we believe - * has only been seen in simulation - */ - if (PCIBR_WAR_ENABLED(PV867308, pcibr_soft) && - (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) { - printk("BRIDGE ERR_STATUS 0x%lx\n", err_status); - pcibr_error_dump(pcibr_soft); - /* machine_error_dump(""); */ - panic("PCI Bridge Error interrupt killed the system"); - } - - if (err_status & BRIDGE_ISR_ERROR_FATAL) { - panic("PCI Bridge Error interrupt killed the system"); - /*NOTREACHED */ - } - - - /* - * We can't return without re-enabling the interrupt, since - * it would cause problems for devices like IOC3 (Lost - * interrupts ?.). So, just cleanup the interrupt, and - * use saved values later.. - * - * PIC doesn't require groups of interrupts to be cleared... - */ - pcireg_intr_reset_set(pcibr_soft, (int_status | BRIDGE_IRR_MULTI_CLR)); - - /* PIC BRINGUP WAR (PV# 856155): - * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from - * the b_arb register to re-enable the device. - */ - if ((err_status & PIC_ISR_PCIX_ARB_ERR) && - PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) { - pcireg_arbitration_bit_set(pcibr_soft, (0xf << 20)); - } - - /* Zero out bserr_intstat field */ - pcibr_soft->bs_errinfo.bserr_intstat = 0; - return IRQ_HANDLED; -} - -/* - * pcibr_addr_toslot - * Given the 'pciaddr' find out which slot this address is - * allocated to, and return the slot number. - * While we have the info handy, construct the - * function number, space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - */ -static int -pcibr_addr_toslot(pcibr_soft_t pcibr_soft, - iopaddr_t pciaddr, - pciio_space_t *spacep, - iopaddr_t *offsetp, - pciio_function_t *funcp) -{ - int s, f = 0, w; - iopaddr_t base; - size_t size; - pciio_piospace_t piosp; - - /* - * Check if the address is in config space - */ - - if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) { - - if (pciaddr >= BRIDGE_CONFIG1_BASE) - pciaddr -= BRIDGE_CONFIG1_BASE; - else - pciaddr -= BRIDGE_CONFIG_BASE; - - s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE; - pciaddr %= BRIDGE_CONFIG_SLOT_SIZE; - - if (funcp) { - f = pciaddr / 0x100; - pciaddr %= 0x100; - } - if (spacep) - *spacep = PCIIO_SPACE_CFG; - if (offsetp) - *offsetp = pciaddr; - if (funcp) - *funcp = f; - - return s; - } - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - for (w = 0; w < 6; w++) { - if (pcibr_info->f_window[w].w_space - == PCIIO_SPACE_NONE) { - continue; - } - base = pcibr_info->f_window[w].w_base; - size = pcibr_info->f_window[w].w_size; - - if ((pciaddr >= base) && (pciaddr < (base + size))) { - if (spacep) - *spacep = PCIIO_SPACE_WIN(w); - if (offsetp) - *offsetp = pciaddr - base; - if (funcp) - *funcp = f; - return s; - } /* endif match */ - } /* next window */ - } /* next func */ - } /* next slot */ - - /* - * Check if the address was allocated as part of the - * pcibr_piospace_alloc calls. - */ - for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) { - int nf = pcibr_soft->bs_slot[s].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos; - - for (f = 0; f < nf; f++) { - pcibr_info_t pcibr_info = pcibr_infoh[f]; - - if (!pcibr_info) - continue; - piosp = pcibr_info->f_piospace; - while (piosp) { - if ((piosp->start <= pciaddr) && - ((piosp->count + piosp->start) > pciaddr)) { - if (spacep) - *spacep = piosp->space; - if (offsetp) - *offsetp = pciaddr - piosp->start; - return s; - } /* endif match */ - piosp = piosp->next; - } /* next piosp */ - } /* next func */ - } /* next slot */ - - /* - * Some other random address on the PCI bus ... - * we have no way of knowing whether this was - * a MEM or I/O access; so, for now, we just - * assume that the low 1G is MEM, the next - * 3G is I/O, and anything above the 4G limit - * is obviously MEM. - */ - - if (spacep) - *spacep = ((pciaddr < (1ul << 30)) ? PCIIO_SPACE_MEM : - (pciaddr < (4ul << 30)) ? PCIIO_SPACE_IO : - PCIIO_SPACE_MEM); - if (offsetp) - *offsetp = pciaddr; - - return PCIIO_SLOT_NONE; - -} - -void -pcibr_error_cleanup(pcibr_soft_t pcibr_soft, int error_code) -{ - uint64_t clr_bits = BRIDGE_IRR_ALL_CLR; - - ASSERT(error_code & IOECODE_PIO); - error_code = error_code; - - pcireg_intr_reset_set(pcibr_soft, clr_bits); - - pcireg_tflush_get(pcibr_soft); /* flushbus */ -} - - -/* - * pcibr_error_extract - * Given the 'pcibr vertex handle' find out which slot - * the bridge status error address (from pcibr_soft info - * hanging off the vertex) - * allocated to, and return the slot number. - * While we have the info handy, construct the - * space code and offset as well. - * - * NOTE: if this routine is called, we don't know whether - * the address is in CFG, MEM, or I/O space. We have to guess. - * This will be the case on PIO stores, where the only way - * we have of getting the address is to check the Bridge, which - * stores the PCI address but not the space and not the xtalk - * address (from which we could get it). - * - * XXX- this interface has no way to return the function - * number on a multifunction card, even though that data - * is available. - */ - -pciio_slot_t -pcibr_error_extract(vertex_hdl_t pcibr_vhdl, - pciio_space_t *spacep, - iopaddr_t *offsetp) -{ - pcibr_soft_t pcibr_soft = 0; - iopaddr_t bserr_addr; - pciio_slot_t slot = PCIIO_SLOT_NONE; - arbitrary_info_t rev; - - /* Do a sanity check as to whether we really got a - * bridge vertex handle. - */ - if (hwgraph_info_get_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, &rev) != - GRAPH_SUCCESS) - return(slot); - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (pcibr_soft) { - bserr_addr = pcireg_pci_bus_addr_get(pcibr_soft); - slot = pcibr_addr_toslot(pcibr_soft, bserr_addr, - spacep, offsetp, NULL); - } - return slot; -} - -/*ARGSUSED */ -void -pcibr_device_disable(pcibr_soft_t pcibr_soft, int devnum) -{ - /* - * XXX - * Device failed to handle error. Take steps to - * disable this device ? HOW TO DO IT ? - * - * If there are any Read response buffers associated - * with this device, it's time to get them back!! - * - * We can disassociate any interrupt level associated - * with this device, and disable that interrupt level - * - * For now it's just a place holder - */ -} - -/* - * pcibr_pioerror - * Handle PIO error that happened at the bridge pointed by pcibr_soft. - * - * Queries the Bus interface attached to see if the device driver - * mapping the device-number that caused error can handle the - * situation. If so, it will clean up any error, and return - * indicating the error was handled. If the device driver is unable - * to handle the error, it expects the bus-interface to disable that - * device, and takes any steps needed here to take away any resources - * associated with this device. - * - * A note about slots: - * - * PIC-based bridges use zero-based device numbering when devices to - * internal registers. However, the physical slots are numbered using a - * one-based scheme because in PCI-X, device 0 is reserved (see comments - * in pcibr_private.h for a better description). - * - * When building up the hwgraph, we use the external (one-based) number - * scheme when numbering slot components so that hwgraph more accuratly - * reflects what is silkscreened on the bricks. - * - * Since pciio_error_handler() needs to ultimatly be able to do a hwgraph - * lookup, the ioerror that gets built up in pcibr_pioerror() encodes the - * external (one-based) slot number. However, loops in pcibr_pioerror() - * which attempt to translate the virtual address into the correct - * PCI physical address use the device (zero-based) numbering when - * walking through bridge structures. - * - * To that end, pcibr_pioerror() uses device to denote the - * zero-based device number, and external_slot to denote the corresponding - * one-based slot number. Loop counters (eg. cs) are always device based. - */ - -/* BEM_ADD_IOE doesn't dump the whole ioerror, it just - * decodes the PCI specific portions -- we count on our - * callers to dump the raw IOE data. - */ -#define BEM_ADD_IOE(ioe) \ - do { \ - if (IOERROR_FIELDVALID(ioe, busspace)) { \ - iopaddr_t spc; \ - iopaddr_t win; \ - short widdev; \ - iopaddr_t busaddr; \ - \ - IOERROR_GETVALUE(spc, ioe, busspace); \ - win = spc - PCIIO_SPACE_WIN(0); \ - IOERROR_GETVALUE(busaddr, ioe, busaddr); \ - IOERROR_GETVALUE(widdev, ioe, widgetdev); \ - \ - switch (spc) { \ - case PCIIO_SPACE_CFG: \ - printk("\tPCI Slot %d Func %d CFG space Offset 0x%lx\n",\ - pciio_widgetdev_slot_get(widdev), \ - pciio_widgetdev_func_get(widdev), \ - busaddr); \ - break; \ - case PCIIO_SPACE_IO: \ - printk("\tPCI I/O space Offset 0x%lx\n", busaddr); \ - break; \ - case PCIIO_SPACE_MEM: \ - case PCIIO_SPACE_MEM32: \ - case PCIIO_SPACE_MEM64: \ - printk("\tPCI MEM space Offset 0x%lx\n", busaddr); \ - break; \ - default: \ - if (win < 6) { \ - printk("\tPCI Slot %d Func %d Window %ld Offset 0x%lx\n",\ - pciio_widgetdev_slot_get(widdev), \ - pciio_widgetdev_func_get(widdev), \ - win, \ - busaddr); \ - } \ - break; \ - } \ - } \ - } while (0) - -/*ARGSUSED */ -int -pcibr_pioerror( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - int retval = IOERROR_HANDLED; - - vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; - iopaddr_t bad_xaddr; - - pciio_space_t raw_space; /* raw PCI space */ - iopaddr_t raw_paddr; /* raw PCI address */ - - pciio_space_t space; /* final PCI space */ - pciio_slot_t device; /* final PCI device if appropriate */ - pciio_slot_t external_slot;/* external slot for device */ - pciio_function_t func; /* final PCI func, if appropriate */ - iopaddr_t offset; /* final PCI offset */ - - int cs, cw, cf; - pciio_space_t wx; - iopaddr_t wb; - size_t ws; - iopaddr_t wl; - - - /* - * We expect to have an "xtalkaddr" coming in, - * and need to construct the slot/space/offset. - */ - - IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, - "pcibr_pioerror: pcibr_soft=0x%lx, bad_xaddr=0x%lx\n", - pcibr_soft, bad_xaddr)); - - device = PCIIO_SLOT_NONE; - func = PCIIO_FUNC_NONE; - raw_space = PCIIO_SPACE_NONE; - raw_paddr = 0; - - if ((bad_xaddr >= PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0)) && - (bad_xaddr < PCIBR_TYPE1_CFG(pcibr_soft))) { - raw_paddr = bad_xaddr - PCIBR_BUS_TYPE0_CFG_DEV(pcibr_soft, 0); - device = raw_paddr / BRIDGE_CONFIG_SLOT_SIZE; - raw_paddr = raw_paddr % BRIDGE_CONFIG_SLOT_SIZE; - raw_space = PCIIO_SPACE_CFG; - } - if ((bad_xaddr >= PCIBR_TYPE1_CFG(pcibr_soft)) && - (bad_xaddr < (PCIBR_TYPE1_CFG(pcibr_soft) + 0x1000))) { - /* Type 1 config space: - * slot and function numbers not known. - * Perhaps we can read them back? - */ - raw_paddr = bad_xaddr - PCIBR_TYPE1_CFG(pcibr_soft); - raw_space = PCIIO_SPACE_CFG; - } - if ((bad_xaddr >= PCIBR_BRIDGE_DEVIO(pcibr_soft, 0)) && - (bad_xaddr < PCIBR_BRIDGE_DEVIO(pcibr_soft, BRIDGE_DEV_CNT))) { - int x; - - raw_paddr = bad_xaddr - PCIBR_BRIDGE_DEVIO(pcibr_soft, 0); - x = raw_paddr / BRIDGE_DEVIO_OFF; - raw_paddr %= BRIDGE_DEVIO_OFF; - /* first two devio windows are double-sized */ - if ((x == 1) || (x == 3)) - raw_paddr += BRIDGE_DEVIO_OFF; - if (x > 0) - x--; - if (x > 1) - x--; - /* x is which devio reg; no guarantee - * PCI slot x will be responding. - * still need to figure out who decodes - * space/offset on the bus. - */ - raw_space = pcibr_soft->bs_slot[x].bss_devio.bssd_space; - if (raw_space == PCIIO_SPACE_NONE) { - /* Someone got an error because they - * accessed the PCI bus via a DevIO(x) - * window that pcibr has not yet assigned - * to any specific PCI address. It is - * quite possible that the Device(x) - * register has been changed since they - * made their access, but we will give it - * our best decode shot. - */ - raw_space = pcibr_soft->bs_slot[x].bss_device - & BRIDGE_DEV_DEV_IO_MEM - ? PCIIO_SPACE_MEM - : PCIIO_SPACE_IO; - raw_paddr += - (pcibr_soft->bs_slot[x].bss_device & - BRIDGE_DEV_OFF_MASK) << - BRIDGE_DEV_OFF_ADDR_SHFT; - } else - raw_paddr += pcibr_soft->bs_slot[x].bss_devio.bssd_base; - } - - if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 0)) { - if ((bad_xaddr >= PICBRIDGE0_PCI_MEM32_BASE) && - (bad_xaddr <= PICBRIDGE0_PCI_MEM32_LIMIT)) { - raw_space = PCIIO_SPACE_MEM32; - raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM32_BASE; - } - if ((bad_xaddr >= PICBRIDGE0_PCI_MEM64_BASE) && - (bad_xaddr <= PICBRIDGE0_PCI_MEM64_LIMIT)) { - raw_space = PCIIO_SPACE_MEM64; - raw_paddr = bad_xaddr - PICBRIDGE0_PCI_MEM64_BASE; - } - } else if (IS_PIC_BUSNUM_SOFT(pcibr_soft, 1)) { - if ((bad_xaddr >= PICBRIDGE1_PCI_MEM32_BASE) && - (bad_xaddr <= PICBRIDGE1_PCI_MEM32_LIMIT)) { - raw_space = PCIIO_SPACE_MEM32; - raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM32_BASE; - } - if ((bad_xaddr >= PICBRIDGE1_PCI_MEM64_BASE) && - (bad_xaddr <= PICBRIDGE1_PCI_MEM64_LIMIT)) { - raw_space = PCIIO_SPACE_MEM64; - raw_paddr = bad_xaddr - PICBRIDGE1_PCI_MEM64_BASE; - } - } else { - printk("pcibr_pioerror(): unknown bridge type"); - return IOERROR_UNHANDLED; - } - space = raw_space; - offset = raw_paddr; - - if ((device == PCIIO_SLOT_NONE) && (space != PCIIO_SPACE_NONE)) { - /* we've got a space/offset but not which - * PCI slot decodes it. Check through our - * notions of which devices decode where. - * - * Yes, this "duplicates" some logic in - * pcibr_addr_toslot; the difference is, - * this code knows which space we are in, - * and can really really tell what is - * going on (no guessing). - */ - - for (cs = pcibr_soft->bs_min_slot; - (cs < PCIBR_NUM_SLOTS(pcibr_soft)) && - (device == PCIIO_SLOT_NONE); cs++) { - int nf = pcibr_soft->bs_slot[cs].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; - - for (cf = 0; (cf < nf) && (device == PCIIO_SLOT_NONE); cf++) { - pcibr_info_t pcibr_info = pcibr_infoh[cf]; - - if (!pcibr_info) - continue; - for (cw = 0; (cw < 6) && (device == PCIIO_SLOT_NONE); ++cw) { - if (((wx = pcibr_info->f_window[cw].w_space) != PCIIO_SPACE_NONE) && - ((wb = pcibr_info->f_window[cw].w_base) != 0) && - ((ws = pcibr_info->f_window[cw].w_size) != 0) && - ((wl = wb + ws) > wb) && - ((wb <= offset) && (wl > offset))) { - /* MEM, MEM32 and MEM64 need to - * compare as equal ... - */ - if ((wx == space) || - (((wx == PCIIO_SPACE_MEM) || - (wx == PCIIO_SPACE_MEM32) || - (wx == PCIIO_SPACE_MEM64)) && - ((space == PCIIO_SPACE_MEM) || - (space == PCIIO_SPACE_MEM32) || - (space == PCIIO_SPACE_MEM64)))) { - device = cs; - func = cf; - space = PCIIO_SPACE_WIN(cw); - offset -= wb; - } /* endif window space match */ - } /* endif window valid and addr match */ - } /* next window unless slot set */ - } /* next func unless slot set */ - } /* next slot unless slot set */ - /* XXX- if slot is still -1, no PCI devices are - * decoding here using their standard PCI BASE - * registers. This would be a really good place - * to cross-coordinate with the pciio PCI - * address space allocation routines, to find - * out if this address is "allocated" by any of - * our subsidiary devices. - */ - } - /* Scan all piomap records on this PCI bus to update - * the TimeOut Counters on all matching maps. If we - * don't already know the slot number, take it from - * the first matching piomap. Note that we have to - * compare maps against raw_space and raw_paddr - * since space and offset could already be - * window-relative. - * - * There is a chance that one CPU could update - * through this path, and another CPU could also - * update due to an interrupt. Closing this hole - * would only result in the possibility of some - * errors never getting logged at all, and since the - * use for bp_toc is as a logical test rather than a - * strict count, the excess counts are not a - * problem. - */ - for (cs = pcibr_soft->bs_min_slot; - cs < PCIBR_NUM_SLOTS(pcibr_soft); ++cs) { - int nf = pcibr_soft->bs_slot[cs].bss_ninfo; - pcibr_info_h pcibr_infoh = pcibr_soft->bs_slot[cs].bss_infos; - - for (cf = 0; cf < nf; cf++) { - pcibr_info_t pcibr_info = pcibr_infoh[cf]; - pcibr_piomap_t map; - - if (!pcibr_info) - continue; - - for (map = pcibr_info->f_piomap; - map != NULL; map = map->bp_next) { - wx = map->bp_space; - wb = map->bp_pciaddr; - ws = map->bp_mapsz; - cw = wx - PCIIO_SPACE_WIN(0); - if (cw >= 0 && cw < 6) { - wb += pcibr_soft->bs_slot[cs].bss_window[cw].bssw_base; - wx = pcibr_soft->bs_slot[cs].bss_window[cw].bssw_space; - } - if (wx == PCIIO_SPACE_ROM) { - wb += pcibr_info->f_rbase; - wx = PCIIO_SPACE_MEM; - } - if ((wx == PCIIO_SPACE_MEM32) || - (wx == PCIIO_SPACE_MEM64)) - wx = PCIIO_SPACE_MEM; - wl = wb + ws; - if ((wx == raw_space) && (raw_paddr >= wb) && (raw_paddr < wl)) { - atomic_inc(&map->bp_toc); - if (device == PCIIO_SLOT_NONE) { - device = cs; - func = cf; - space = map->bp_space; - if (cw >= 0 && cw < 6) - offset -= pcibr_soft->bs_slot[device].bss_window[cw].bssw_base; - } - - break; - } - } - } - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, - "pcibr_pioerror: space=%d, offset=0x%lx, dev=0x%x, func=0x%x\n", - space, offset, device, func)); - - if (space != PCIIO_SPACE_NONE) { - if (device != PCIIO_SLOT_NONE) { - external_slot = PCIBR_DEVICE_TO_SLOT(pcibr_soft, device); - - if (func != PCIIO_FUNC_NONE) - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(external_slot,func)); - else - IOERROR_SETVALUE(ioe, widgetdev, - pciio_widgetdev_create(external_slot,0)); - } - IOERROR_SETVALUE(ioe, busspace, space); - IOERROR_SETVALUE(ioe, busaddr, offset); - } - if (mode == MODE_DEVPROBE) { - /* - * During probing, we don't really care what the - * error is. Clean up the error in Bridge, notify - * subsidiary devices, and return success. - */ - pcibr_error_cleanup(pcibr_soft, error_code); - - /* if appropriate, give the error handler for this slot - * a shot at this probe access as well. - */ - return (device == PCIIO_SLOT_NONE) ? IOERROR_HANDLED : - pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - } - /* - * If we don't know what "PCI SPACE" the access - * was targeting, we may have problems at the - * Bridge itself. Don't touch any bridge registers, - * and do complain loudly. - */ - - if (space == PCIIO_SPACE_NONE) { - printk("XIO Bus Error at %s\n" - "\taccess to XIO bus offset 0x%lx\n" - "\tdoes not correspond to any PCI address\n", - pcibr_soft->bs_name, bad_xaddr); - - /* caller will dump contents of ioe struct */ - return IOERROR_XTALKLEVEL; - } - - /* - * Actual PCI Error handling situation. - * Typically happens when a user level process accesses - * PCI space, and it causes some error. - * - * Due to PCI Bridge implementation, we get two indication - * for a read error: an interrupt and a Bus error. - * We like to handle read error in the bus error context. - * But the interrupt comes and goes before bus error - * could make much progress. (NOTE: interrupd does - * come in _after_ bus error processing starts. But it's - * completed by the time bus error code reaches PCI PIO - * error handling. - * Similarly write error results in just an interrupt, - * and error handling has to be done at interrupt level. - * There is no way to distinguish at interrupt time, if an - * error interrupt is due to read/write error.. - */ - - /* We know the xtalk addr, the raw PCI bus space, - * the raw PCI bus address, the decoded PCI bus - * space, the offset within that space, and the - * decoded PCI slot (which may be "PCIIO_SLOT_NONE" if no slot - * is known to be involved). - */ - - /* - * Hand the error off to the handler registered - * for the slot that should have decoded the error, - * or to generic PCI handling (if pciio decides that - * such is appropriate). - */ - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - - if (retval != IOERROR_HANDLED) { - - /* Generate a generic message for IOERROR_UNHANDLED - * since the subsidiary handlers were silent, and - * did no recovery. - */ - if (retval == IOERROR_UNHANDLED) { - retval = IOERROR_PANIC; - - /* we may or may not want to print some of this, - * depending on debug level and which error code. - */ - - printk(KERN_ALERT - "PIO Error on PCI Bus %s", - pcibr_soft->bs_name); - BEM_ADD_IOE(ioe); - } - - /* - * Since error could not be handled at lower level, - * error data logged has not been cleared. - * Clean up errors, and - * re-enable bridge to interrupt on error conditions. - * NOTE: Wheather we get the interrupt on PCI_ABORT or not is - * dependent on INT_ENABLE register. This write just makes sure - * that if the interrupt was enabled, we do get the interrupt. - * - * CAUTION: Resetting bit BRIDGE_IRR_PCI_GRP_CLR, acknowledges - * a group of interrupts. If while handling this error, - * some other error has occurred, that would be - * implicitly cleared by this write. - * Need a way to ensure we don't inadvertently clear some - * other errors. - */ - if (IOERROR_FIELDVALID(ioe, widgetdev)) { - short widdev; - IOERROR_GETVALUE(widdev, ioe, widgetdev); - external_slot = pciio_widgetdev_slot_get(widdev); - device = PCIBR_SLOT_TO_DEVICE(pcibr_soft, external_slot); - pcibr_device_disable(pcibr_soft, device); - } - if (mode == MODE_DEVUSERERROR) - pcibr_error_cleanup(pcibr_soft, error_code); - } - return retval; -} - -/* - * bridge_dmaerror - * Some error was identified in a DMA transaction. - * This routine will identify the that caused the error, - * and try to invoke the appropriate bus service to handle this. - */ - -int -pcibr_dmard_error( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; - int retval = 0; - int bufnum, device; - - /* - * In case of DMA errors, bridge should have logged the - * address that caused the error. - * Look up the address, in the bridge error registers, and - * take appropriate action - */ - { - short tmp; - IOERROR_GETVALUE(tmp, ioe, widgetnum); - ASSERT(tmp == pcibr_soft->bs_xid); - } - - /* - * read error log registers - */ - bufnum = pcireg_resp_err_buf_get(pcibr_soft); - device = pcireg_resp_err_dev_get(pcibr_soft); - IOERROR_SETVALUE(ioe, widgetdev, pciio_widgetdev_create(device, 0)); - IOERROR_SETVALUE(ioe, busaddr, pcireg_resp_err_get(pcibr_soft)); - - /* - * need to ensure that the xtalk address in ioe - * maps to PCI error address read from bridge. - * How to convert PCI address back to Xtalk address ? - * (better idea: convert XTalk address to PCI address - * and then do the compare!) - */ - - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - if (retval != IOERROR_HANDLED) { - short tmp; - IOERROR_GETVALUE(tmp, ioe, widgetdev); - pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp)); - } - - /* - * Re-enable bridge to interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR - * NOTE: Wheather we get the interrupt on BRIDGE_IRR_RESP_BUF_GRP_CLR or - * not is dependent on INT_ENABLE register. This write just makes sure - * that if the interrupt was enabled, we do get the interrupt. - */ - pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_RESP_BUF_GRP_CLR); - - /* - * Also, release the "bufnum" back to buffer pool that could be re-used. - * This is done by "disabling" the buffer for a moment, then restoring - * the original assignment. - */ - - { - uint64_t rrb_reg; - uint64_t mask; - - rrb_reg = pcireg_rrb_get(pcibr_soft, (bufnum & 1)); - mask = 0xF << ((bufnum >> 1) * 4); - pcireg_rrb_set(pcibr_soft, (bufnum & 1), (rrb_reg & ~mask)); - pcireg_rrb_set(pcibr_soft, (bufnum & 1), rrb_reg); - } - - return retval; -} - -/* - * pcibr_dmawr_error: - * Handle a dma write error caused by a device attached to this bridge. - * - * ioe has the widgetnum, widgetdev, and memaddr fields updated - * But we don't know the PCI address that corresponds to "memaddr" - * nor do we know which device driver is generating this address. - * - * There is no easy way to find out the PCI address(es) that map - * to a specific system memory address. Bus handling code is also - * of not much help, since they don't keep track of the DMA mapping - * that have been handed out. - * So it's a dead-end at this time. - * - * If translation is available, we could invoke the error handling - * interface of the device driver. - */ -/*ARGSUSED */ -int -pcibr_dmawr_error( - pcibr_soft_t pcibr_soft, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - vertex_hdl_t pcibr_vhdl = pcibr_soft->bs_vhdl; - int retval; - - retval = pciio_error_handler(pcibr_vhdl, error_code, mode, ioe); - - if (retval != IOERROR_HANDLED) { - short tmp; - - IOERROR_GETVALUE(tmp, ioe, widgetdev); - pcibr_device_disable(pcibr_soft, pciio_widgetdev_slot_get(tmp)); - } - return retval; -} - -/* - * Bridge error handler. - * Interface to handle all errors that involve bridge in some way. - * - * This normally gets called from xtalk error handler. - * ioe has different set of fields set depending on the error that - * was encountered. So, we have a bit field indicating which of the - * fields are valid. - * - * NOTE: This routine could be operating in interrupt context. So, - * don't try to sleep here (till interrupt threads work!!) - */ -int -pcibr_error_handler( - error_handler_arg_t einfo, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - pcibr_soft_t pcibr_soft; - int retval = IOERROR_BADERRORCODE; - - pcibr_soft = (pcibr_soft_t) einfo; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, - "pcibr_error_handler: pcibr_soft=0x%lx, error_code=0x%x\n", - pcibr_soft, error_code)); - -#if DEBUG && ERROR_DEBUG - printk( "%s: pcibr_error_handler\n", pcibr_soft->bs_name); -#endif - - ASSERT(pcibr_soft != NULL); - - if (error_code & IOECODE_PIO) - retval = pcibr_pioerror(pcibr_soft, error_code, mode, ioe); - - if (error_code & IOECODE_DMA) { - if (error_code & IOECODE_READ) { - /* - * DMA read error occurs when a device attached to the bridge - * tries to read some data from system memory, and this - * either results in a timeout or access error. - * First case is indicated by the bit "XREAD_REQ_TOUT" - * and second case by "RESP_XTALK_ERROR" bit in bridge error - * interrupt status register. - * - * pcibr_error_intr_handler would get invoked first, and it has - * the responsibility of calling pcibr_error_handler with - * suitable parameters. - */ - - retval = pcibr_dmard_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); - } - if (error_code & IOECODE_WRITE) { - /* - * A device attached to this bridge has been generating - * bad DMA writes. Find out the device attached, and - * slap on it's wrist. - */ - - retval = pcibr_dmawr_error(pcibr_soft, error_code, MODE_DEVERROR, ioe); - } - } - return retval; - -} - -/* - * PIC has 2 busses under a single widget so pcibr_attach2 registers this - * wrapper function rather than pcibr_error_handler() for PIC. It's upto - * this wrapper to call pcibr_error_handler() with the correct pcibr_soft - * struct (ie. the pcibr_soft struct for the bus that saw the error). - * - * NOTE: this wrapper function is only registered for PIC ASICs and will - * only be called for a PIC - */ -int -pcibr_error_handler_wrapper( - error_handler_arg_t einfo, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioe) -{ - pcibr_soft_t pcibr_soft = (pcibr_soft_t) einfo; - int pio_retval = -1; - int dma_retval = -1; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ERROR_HDLR, pcibr_soft->bs_conn, - "pcibr_error_handler_wrapper: pcibr_soft=0x%lx, " - "error_code=0x%x\n", pcibr_soft, error_code)); - - /* - * It is possible that both a IOECODE_PIO and a IOECODE_DMA, and both - * IOECODE_READ and IOECODE_WRITE could be set in error_code so we must - * process all. Since we are a wrapper for pcibr_error_handler(), and - * will be calling it several times within this routine, we turn off the - * error_code bits we don't want it to be processing during that call. - */ - /* - * If the error was a result of a PIO, we tell what bus on the PIC saw - * the error from the PIO address. - */ - - if (error_code & IOECODE_PIO) { - iopaddr_t bad_xaddr; - /* - * PIC bus0 PIO space 0x000000 - 0x7fffff or 0x40000000 - 0xbfffffff - * bus1 PIO space 0x800000 - 0xffffff or 0xc0000000 - 0x13fffffff - */ - IOERROR_GETVALUE(bad_xaddr, ioe, xtalkaddr); - if ((bad_xaddr <= 0x7fffff) || - ((bad_xaddr >= 0x40000000) && (bad_xaddr <= 0xbfffffff))) { - /* bus 0 saw the error */ - pio_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - (error_code & ~IOECODE_DMA), mode, ioe); - } else if (((bad_xaddr >= 0x800000) && (bad_xaddr <= 0xffffff)) || - ((bad_xaddr >= 0xc0000000) && (bad_xaddr <= 0x13fffffff))) { - /* bus 1 saw the error */ - pcibr_soft = pcibr_soft->bs_peers_soft; - if (!pcibr_soft) { -#if DEBUG - printk(KERN_WARNING "pcibr_error_handler: " - "bs_peers_soft==NULL. bad_xaddr= 0x%lx mode= 0x%lx\n", - bad_xaddr, mode); -#endif - pio_retval = IOERROR_HANDLED; - } else - pio_retval= pcibr_error_handler((error_handler_arg_t)pcibr_soft, - (error_code & ~IOECODE_DMA), mode, ioe); - } else { - printk(KERN_WARNING "pcibr_error_handler_wrapper(): IOECODE_PIO: " - "saw an invalid pio address: 0x%lx\n", bad_xaddr); - pio_retval = IOERROR_UNHANDLED; - } - } - - /* - * If the error was a result of a DMA Write, we tell what bus on the PIC - * saw the error by looking at tnum. - */ - if ((error_code & IOECODE_DMA) && (error_code & IOECODE_WRITE)) { - short tmp; - /* - * For DMA writes [X]Bridge encodes the TNUM field of a Xtalk - * packet like this: - * bits value - * 4:3 10b - * 2:0 device number - * - * BUT PIC needs the bus number so it does this: - * bits value - * 4:3 10b - * 2 busnumber - * 1:0 device number - * - * Pull out the bus number from `tnum' and reset the `widgetdev' - * since when hubiio_crb_error_handler() set `widgetdev' it had - * no idea if it was a PIC or a BRIDGE ASIC so it set it based - * off bits 2:0 - */ - IOERROR_GETVALUE(tmp, ioe, tnum); - IOERROR_SETVALUE(ioe, widgetdev, (tmp & 0x3)); - if ((tmp & 0x4) == 0) { - /* bus 0 saw the error. */ - dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe); - } else { - /* bus 1 saw the error */ - pcibr_soft = pcibr_soft->bs_peers_soft; - dma_retval = pcibr_error_handler((error_handler_arg_t)pcibr_soft, - (error_code & ~(IOECODE_PIO|IOECODE_READ)), mode, ioe); - } - } - - /* - * If the error was a result of a DMA READ, XXX ??? - */ - if ((error_code & IOECODE_DMA) && (error_code & IOECODE_READ)) { - /* - * A DMA Read error will result in a BRIDGE_ISR_RESP_XTLK_ERR - * or BRIDGE_ISR_BAD_XRESP_PKT bridge error interrupt which - * are fatal interrupts (ie. BRIDGE_ISR_ERROR_FATAL) causing - * pcibr_error_intr_handler() to panic the system. So is the - * error handler even going to get called??? It appears that - * the pcibr_dmard_error() attempts to clear the interrupts - * so pcibr_error_intr_handler() won't see them, but there - * appears to be nothing to prevent pcibr_error_intr_handler() - * from running before pcibr_dmard_error() has a chance to - * clear the interrupt. - * - * Since we'll be panicing anyways, don't bother handling the - * error for now until we can fix this race condition mentioned - * above. - */ - dma_retval = IOERROR_UNHANDLED; - } - - /* XXX: pcibr_error_handler() should probably do the same thing, it over- - * write it's return value as it processes the different "error_code"s. - */ - if ((pio_retval == -1) && (dma_retval == -1)) { - return IOERROR_BADERRORCODE; - } else if ((dma_retval != IOERROR_HANDLED) && (dma_retval != -1)) { - return dma_retval; - } else if ((pio_retval != IOERROR_HANDLED) && (pio_retval != -1)) { - return pio_retval; - } else { - return IOERROR_HANDLED; - } -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c deleted file mode 100644 index 7bb247257..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_hints.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); -void pcibr_hints_fix_rrbs(vertex_hdl_t); -void pcibr_hints_dualslot(vertex_hdl_t, pciio_slot_t, pciio_slot_t); -void pcibr_hints_intr_bits(vertex_hdl_t, pcibr_intr_bits_f *); -void pcibr_set_rrb_callback(vertex_hdl_t, rrb_alloc_funct_t); -void pcibr_hints_handsoff(vertex_hdl_t); -void pcibr_hints_subdevs(vertex_hdl_t, pciio_slot_t, uint64_t); - -pcibr_hints_t -pcibr_hints_get(vertex_hdl_t xconn_vhdl, int alloc) -{ - arbitrary_info_t ainfo = 0; - graph_error_t rv; - pcibr_hints_t hint; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (alloc && (rv != GRAPH_SUCCESS)) { - - hint = kmalloc(sizeof (*(hint)), GFP_KERNEL); - if ( !hint ) { - printk(KERN_WARNING "pcibr_hints_get(): unable to allocate " - "memory\n"); - goto abnormal_exit; - } - memset(hint, 0, sizeof (*(hint))); - - hint->rrb_alloc_funct = NULL; - hint->ph_intr_bits = NULL; - rv = hwgraph_info_add_LBL(xconn_vhdl, - INFO_LBL_PCIBR_HINTS, - (arbitrary_info_t) hint); - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - rv = hwgraph_info_get_LBL(xconn_vhdl, INFO_LBL_PCIBR_HINTS, &ainfo); - - if (rv != GRAPH_SUCCESS) - goto abnormal_exit; - - if (ainfo != (arbitrary_info_t) hint) - goto abnormal_exit; - } - return (pcibr_hints_t) ainfo; - -abnormal_exit: - kfree(hint); - return NULL; - -} - -void -pcibr_hints_fix_some_rrbs(vertex_hdl_t xconn_vhdl, unsigned mask) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_rrb_fixed = mask; - else - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_fix_rrbs: pcibr_hints_get failed\n")); -} - -void -pcibr_hints_fix_rrbs(vertex_hdl_t xconn_vhdl) -{ - pcibr_hints_fix_some_rrbs(xconn_vhdl, 0xFF); -} - -void -pcibr_hints_dualslot(vertex_hdl_t xconn_vhdl, - pciio_slot_t host, - pciio_slot_t guest) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_host_slot[guest] = host + 1; - else - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_dualslot: pcibr_hints_get failed\n")); -} - -void -pcibr_hints_intr_bits(vertex_hdl_t xconn_vhdl, - pcibr_intr_bits_f *xxx_intr_bits) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_intr_bits = xxx_intr_bits; - else - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_intr_bits: pcibr_hints_get failed\n")); -} - -void -pcibr_set_rrb_callback(vertex_hdl_t xconn_vhdl, rrb_alloc_funct_t rrb_alloc_funct) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->rrb_alloc_funct = rrb_alloc_funct; -} - -void -pcibr_hints_handsoff(vertex_hdl_t xconn_vhdl) -{ - pcibr_hints_t hint = pcibr_hints_get(xconn_vhdl, 1); - - if (hint) - hint->ph_hands_off = 1; - else - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_handsoff: pcibr_hints_get failed\n")); -} - -void -pcibr_hints_subdevs(vertex_hdl_t xconn_vhdl, - pciio_slot_t slot, - uint64_t subdevs) -{ - arbitrary_info_t ainfo = 0; - char sdname[16]; - vertex_hdl_t pconn_vhdl = GRAPH_VERTEX_NONE; - - sprintf(sdname, "%s/%d", EDGE_LBL_PCI, slot); - (void) hwgraph_path_add(xconn_vhdl, sdname, &pconn_vhdl); - if (pconn_vhdl == GRAPH_VERTEX_NONE) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_subdevs: hwgraph_path_create failed\n")); - return; - } - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == 0) { - uint64_t *subdevp; - - subdevp = kmalloc(sizeof (*(subdevp)), GFP_KERNEL); - if (!subdevp) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_subdevs: subdev ptr alloc failed\n")); - return; - } - memset(subdevp, 0, sizeof (*(subdevp))); - *subdevp = subdevs; - hwgraph_info_add_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, (arbitrary_info_t) subdevp); - hwgraph_info_get_LBL(pconn_vhdl, INFO_LBL_SUBDEVS, &ainfo); - if (ainfo == (arbitrary_info_t) subdevp) - return; - kfree(subdevp); - if (ainfo == (arbitrary_info_t) NULL) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_hints_subdevs: null subdevs ptr\n")); - return; - } - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, xconn_vhdl, - "pcibr_subdevs_get: dup subdev add_LBL\n")); - } - *(uint64_t *) ainfo = subdevs; -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c deleted file mode 100644 index 2674b92ef..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __ia64 -inline int -compare_and_swap_ptr(void **location, void *old_ptr, void *new_ptr) -{ - /* FIXME - compare_and_swap_ptr NOT ATOMIC */ - if (*location == old_ptr) { - *location = new_ptr; - return 1; - } - else - return 0; -} -#endif - -unsigned int pcibr_intr_bits(pciio_info_t info, pciio_intr_line_t lines, int nslots); -pcibr_intr_t pcibr_intr_alloc(vertex_hdl_t, device_desc_t, pciio_intr_line_t, vertex_hdl_t); -void pcibr_intr_free(pcibr_intr_t); -void pcibr_setpciint(xtalk_intr_t); -int pcibr_intr_connect(pcibr_intr_t, intr_func_t, intr_arg_t); -void pcibr_intr_disconnect(pcibr_intr_t); - -vertex_hdl_t pcibr_intr_cpu_get(pcibr_intr_t); - -extern pcibr_info_t pcibr_info_get(vertex_hdl_t); - -/* ===================================================================== - * INTERRUPT MANAGEMENT - */ - -unsigned int -pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines, int nslots) -{ - pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(info); - unsigned bbits = 0; - - /* - * Currently favored mapping from PCI - * slot number and INTA/B/C/D to Bridge - * PCI Interrupt Bit Number: - * - * SLOT A B C D - * 0 0 4 0 4 - * 1 1 5 1 5 - * 2 2 6 2 6 - * 3 3 7 3 7 - * 4 4 0 4 0 - * 5 5 1 5 1 - * 6 6 2 6 2 - * 7 7 3 7 3 - */ - - if (slot < nslots) { - if (lines & (PCIIO_INTR_LINE_A| PCIIO_INTR_LINE_C)) - bbits |= 1 << slot; - if (lines & (PCIIO_INTR_LINE_B| PCIIO_INTR_LINE_D)) - bbits |= 1 << (slot ^ 4); - } - return bbits; -} - - -/* - * On SN systems there is a race condition between a PIO read response - * and DMA's. In rare cases, the read response may beat the DMA, causing - * the driver to think that data in memory is complete and meaningful. - * This code eliminates that race. - * This routine is called by the PIO read routines after doing the read. - * This routine then forces a fake interrupt on another line, which - * is logically associated with the slot that the PIO is addressed to. - * (see sn_dma_flush_init() ) - * It then spins while watching the memory location that the interrupt - * is targetted to. When the interrupt response arrives, we are sure - * that the DMA has landed in memory and it is safe for the driver - * to proceed. - */ - -extern struct sn_flush_nasid_entry flush_nasid_list[MAX_NASIDS]; - -void -sn_dma_flush(unsigned long addr) -{ - nasid_t nasid; - int wid_num; - struct sn_flush_device_list *p; - int i,j; - int bwin; - unsigned long flags; - - nasid = NASID_GET(addr); - wid_num = SWIN_WIDGETNUM(addr); - bwin = BWIN_WINDOWNUM(addr); - - if (flush_nasid_list[nasid].widget_p == NULL) return; - if (bwin > 0) { - unsigned long itte = flush_nasid_list[nasid].iio_itte[bwin]; - - wid_num = (itte >> IIO_ITTE_WIDGET_SHIFT) & - IIO_ITTE_WIDGET_MASK; - } - if (flush_nasid_list[nasid].widget_p == NULL) return; - if (flush_nasid_list[nasid].widget_p[wid_num] == NULL) return; - p = &flush_nasid_list[nasid].widget_p[wid_num][0]; - - /* find a matching BAR */ - - for (i=0; ibar_list[j].start == 0) break; - if (addr >= p->bar_list[j].start && addr <= p->bar_list[j].end) break; - } - if (j < PCI_ROM_RESOURCE && p->bar_list[j].start != 0) break; - p++; - } - - /* if no matching BAR, return without doing anything. */ - - if (i == DEV_PER_WIDGET) return; - - spin_lock_irqsave(&p->flush_lock, flags); - - p->flush_addr = 0; - - /* force an interrupt. */ - - *(volatile uint32_t *)(p->force_int_addr) = 1; - - /* wait for the interrupt to come back. */ - - while (p->flush_addr != 0x10f); - - /* okay, everything is synched up. */ - spin_unlock_irqrestore(&p->flush_lock, flags); -} - -EXPORT_SYMBOL(sn_dma_flush); - -/* - * There are end cases where a deadlock can occur if interrupt - * processing completes and the Bridge b_int_status bit is still set. - * - * One scenerio is if a second PCI interrupt occurs within 60ns of - * the previous interrupt being cleared. In this case the Bridge - * does not detect the transition, the Bridge b_int_status bit - * remains set, and because no transition was detected no interrupt - * packet is sent to the Hub/Heart. - * - * A second scenerio is possible when a b_int_status bit is being - * shared by multiple devices: - * Device #1 generates interrupt - * Bridge b_int_status bit set - * Device #2 generates interrupt - * interrupt processing begins - * ISR for device #1 runs and - * clears interrupt - * Device #1 generates interrupt - * ISR for device #2 runs and - * clears interrupt - * (b_int_status bit still set) - * interrupt processing completes - * - * Interrupt processing is now complete, but an interrupt is still - * outstanding for Device #1. But because there was no transition of - * the b_int_status bit, no interrupt packet will be generated and - * a deadlock will occur. - * - * To avoid these deadlock situations, this function is used - * to check if a specific Bridge b_int_status bit is set, and if so, - * cause the setting of the corresponding interrupt bit. - * - * On a XBridge (SN1) and PIC (SN2), we do this by writing the appropriate Bridge Force - * Interrupt register. - */ -void -pcibr_force_interrupt(pcibr_intr_t intr) -{ - unsigned bit; - unsigned bits; - pcibr_soft_t pcibr_soft = intr->bi_soft; - - bits = intr->bi_ibits; - for (bit = 0; bit < 8; bit++) { - if (bits & (1 << bit)) { - - PCIBR_DEBUG((PCIBR_DEBUG_INTR, pcibr_soft->bs_vhdl, - "pcibr_force_interrupt: bit=0x%x\n", bit)); - - pcireg_force_intr_set(pcibr_soft, bit); - } - } -} - -/*ARGSUSED */ -pcibr_intr_t -pcibr_intr_alloc(vertex_hdl_t pconn_vhdl, - device_desc_t dev_desc, - pciio_intr_line_t lines, - vertex_hdl_t owner_dev) -{ - pcibr_info_t pcibr_info = pcibr_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pcibr_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pcibr_info->f_mfast; - vertex_hdl_t xconn_vhdl = pcibr_soft->bs_conn; - int is_threaded = 0; - - xtalk_intr_t *xtalk_intr_p; - pcibr_intr_t *pcibr_intr_p; - pcibr_intr_list_t *intr_list_p; - - unsigned pcibr_int_bits; - unsigned pcibr_int_bit; - xtalk_intr_t xtalk_intr = (xtalk_intr_t)0; - hub_intr_t hub_intr; - pcibr_intr_t pcibr_intr; - pcibr_intr_list_t intr_entry; - pcibr_intr_list_t intr_list; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "pcibr_intr_alloc: %s%s%s%s%s\n", - !(lines & 15) ? " No INTs?" : "", - lines & 1 ? " INTA" : "", - lines & 2 ? " INTB" : "", - lines & 4 ? " INTC" : "", - lines & 8 ? " INTD" : "")); - - pcibr_intr = kmalloc(sizeof (*(pcibr_intr)), GFP_KERNEL); - if (!pcibr_intr) - return NULL; - memset(pcibr_intr, 0, sizeof (*(pcibr_intr))); - - pcibr_intr->bi_dev = pconn_vhdl; - pcibr_intr->bi_lines = lines; - pcibr_intr->bi_soft = pcibr_soft; - pcibr_intr->bi_ibits = 0; /* bits will be added below */ - pcibr_intr->bi_func = 0; /* unset until connect */ - pcibr_intr->bi_arg = 0; /* unset until connect */ - pcibr_intr->bi_flags = is_threaded ? 0 : PCIIO_INTR_NOTHREAD; - pcibr_intr->bi_mustruncpu = CPU_NONE; - pcibr_intr->bi_ibuf.ib_in = 0; - pcibr_intr->bi_ibuf.ib_out = 0; - spin_lock_init(&pcibr_intr->bi_ibuf.ib_lock); - - pcibr_int_bits = pcibr_soft->bs_intr_bits((pciio_info_t)pcibr_info, - lines, PCIBR_NUM_SLOTS(pcibr_soft)); - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "pcibr_intr_alloc: pcibr_int_bits: 0x%x\n", pcibr_int_bits)); - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit ++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - xtalk_intr_p = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - xtalk_intr = *xtalk_intr_p; - - if (xtalk_intr == NULL) { - /* - * This xtalk_intr_alloc is constrained for two reasons: - * 1) Normal interrupts and error interrupts need to be delivered - * through a single xtalk target widget so that there aren't any - * ordering problems with DMA, completion interrupts, and error - * interrupts. (Use of xconn_vhdl forces this.) - * - * 2) On SN1, addressing constraints on SN1 and Bridge force - * us to use a single PI number for all interrupts from a - * single Bridge. (SN1-specific code forces this). - */ - - /* - * All code dealing with threaded PCI interrupt handlers - * is located at the pcibr level. Because of this, - * we always want the lower layers (hub/heart_intr_alloc, - * intr_level_connect) to treat us as non-threaded so we - * don't set up a duplicate threaded environment. We make - * this happen by calling a special xtalk interface. - */ - xtalk_intr = xtalk_intr_alloc_nothd(xconn_vhdl, dev_desc, - owner_dev); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "pcibr_intr_alloc: xtalk_intr=0x%lx\n", xtalk_intr)); - - /* both an assert and a runtime check on this: - * we need to check in non-DEBUG kernels, and - * the ASSERT gets us more information when - * we use DEBUG kernels. - */ - ASSERT(xtalk_intr != NULL); - if (xtalk_intr == NULL) { - /* it is quite possible that our - * xtalk_intr_alloc failed because - * someone else got there first, - * and we can find their results - * in xtalk_intr_p. - */ - if (!*xtalk_intr_p) { - printk(KERN_ALERT "pcibr_intr_alloc %s: " - "unable to get xtalk interrupt resources", - pcibr_soft->bs_name); - /* yes, we leak resources here. */ - return 0; - } - } else if (compare_and_swap_ptr((void **) xtalk_intr_p, NULL, xtalk_intr)) { - /* - * now tell the bridge which slot is - * using this interrupt line. - */ - pcireg_intr_device_bit_clr(pcibr_soft, - BRIDGE_INT_DEV_MASK(pcibr_int_bit)); - pcireg_intr_device_bit_set(pcibr_soft, - (pciio_slot << BRIDGE_INT_DEV_SHFT(pcibr_int_bit))); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "bridge intr bit %d clears my wrb\n", - pcibr_int_bit)); - } else { - /* someone else got one allocated first; - * free the one we just created, and - * retrieve the one they allocated. - */ - xtalk_intr_free(xtalk_intr); - xtalk_intr = *xtalk_intr_p; - } - } - - pcibr_intr->bi_ibits |= 1 << pcibr_int_bit; - - intr_entry = kmalloc(sizeof (*(intr_entry)), GFP_KERNEL); - if ( !intr_entry ) { - printk(KERN_ALERT "pcibr_intr_alloc %s: " - "unable to get memory", - pcibr_soft->bs_name); - return 0; - } - memset(intr_entry, 0, sizeof (*(intr_entry))); - - intr_entry->il_next = NULL; - intr_entry->il_intr = pcibr_intr; - intr_entry->il_soft = pcibr_soft; - intr_entry->il_slot = pciio_slot; - intr_list_p = - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "Bridge bit 0x%x wrap=0x%lx\n", pcibr_int_bit, - &(pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap))); - - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the first interrupt on this bridge bit. - */ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "INT 0x%x (bridge bit %d) allocated [FIRST]\n", - pcibr_int_bits, pcibr_int_bit)); - continue; - } - intr_list = *intr_list_p; - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* first entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - kfree(intr_entry); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "INT 0x%x (bridge bit %d) replaces erased first\n", - pcibr_int_bits, pcibr_int_bit)); - continue; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* we are the new second interrupt on this bit. - */ - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared = 1; - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "INT 0x%x (bridge bit %d) is new SECOND\n", - pcibr_int_bits, pcibr_int_bit)); - continue; - } - while (1) { - pcibr_intr_p = &intr_list->il_intr; - if (compare_and_swap_ptr((void **) pcibr_intr_p, NULL, pcibr_intr)) { - /* an entry on list was erased, - * and we replaced it, so we - * don't need our intr_entry. - */ - kfree(intr_entry); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "INT 0x%x (bridge bit %d) replaces erase Nth\n", - pcibr_int_bits, pcibr_int_bit)); - break; - } - intr_list_p = &intr_list->il_next; - if (compare_and_swap_ptr((void **) intr_list_p, NULL, intr_entry)) { - /* entry appended to share list - */ - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "INT 0x%x (bridge bit %d) is new Nth\n", - pcibr_int_bits, pcibr_int_bit)); - break; - } - /* step to next record in chain - */ - intr_list = *intr_list_p; - } - } - } - - hub_intr = (hub_intr_t)xtalk_intr; - pcibr_intr->bi_irq = hub_intr->i_bit; - pcibr_intr->bi_cpu = hub_intr->i_cpuid; - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pconn_vhdl, - "pcibr_intr_alloc complete: pcibr_intr=0x%lx\n", pcibr_intr)); - return pcibr_intr; -} - -/*ARGSUSED */ -void -pcibr_intr_free(pcibr_intr_t pcibr_intr) -{ - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bit; - pcibr_intr_list_t intr_list; - int intr_shared; - xtalk_intr_t *xtalk_intrp; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) { - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - for (intr_list = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_list; - intr_list != NULL; - intr_list = intr_list->il_next) - if (compare_and_swap_ptr((void **) &intr_list->il_intr, - pcibr_intr, - NULL)) { - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, - pcibr_intr->bi_dev, - "pcibr_intr_free: cleared hdlr from bit 0x%x\n", - pcibr_int_bit)); - } - /* If this interrupt line is not being shared between multiple - * devices release the xtalk interrupt resources. - */ - intr_shared = - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared; - xtalk_intrp = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - - if ((!intr_shared) && (*xtalk_intrp)) { - - xtalk_intr_free(*xtalk_intrp); - *xtalk_intrp = 0; - - /* Clear the PCI device interrupt to bridge interrupt pin - * mapping. - */ - pcireg_intr_device_bit_clr(pcibr_soft, - BRIDGE_INT_DEV_MASK(pcibr_int_bit)); - } - } - } - kfree(pcibr_intr); -} - -void -pcibr_setpciint(xtalk_intr_t xtalk_intr) -{ - iopaddr_t addr; - xtalk_intr_vector_t vect; - vertex_hdl_t vhdl; - int bus_num; - int pcibr_int_bit; - void *bridge; - - addr = xtalk_intr_addr_get(xtalk_intr); - vect = xtalk_intr_vector_get(xtalk_intr); - vhdl = xtalk_intr_dev_get(xtalk_intr); - - /* bus and int_bits are stored in sfarg, bus bit3, int_bits bit2:0 */ - pcibr_int_bit = *((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x7; - bus_num = ((*((int *)xtalk_intr_sfarg_get(xtalk_intr)) & 0x8) >> 3); - - bridge = pcibr_bridge_ptr_get(vhdl, bus_num); - pcireg_bridge_intr_addr_vect_set(bridge, pcibr_int_bit, vect); - pcireg_bridge_intr_addr_addr_set(bridge, pcibr_int_bit, addr); -} - -/*ARGSUSED */ -int -pcibr_intr_connect(pcibr_intr_t pcibr_intr, intr_func_t intr_func, intr_arg_t intr_arg) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - unsigned long s; - - if (pcibr_intr == NULL) - return -1; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_intr_connect: intr_func=0x%lx, intr_arg=0x%lx\n", - intr_func, intr_arg)); - - pcibr_intr->bi_func = intr_func; - pcibr_intr->bi_arg = intr_arg; - *((volatile unsigned *)&pcibr_intr->bi_flags) |= PCIIO_INTR_CONNECTED; - - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and make sure there are xtalk resources - * allocated for it. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - pcibr_intr_wrap_t intr_wrap; - xtalk_intr_t xtalk_intr; - void *int_addr; - - xtalk_intr = pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr; - intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - - /* - * If this interrupt line is being shared and the connect has - * already been done, no need to do it again. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected) - continue; - - - /* - * Use the pcibr wrapper function to handle all Bridge interrupts - * regardless of whether the interrupt line is shared or not. - */ - int_addr = pcireg_intr_addr_addr(pcibr_soft, pcibr_int_bit); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = - ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); - xtalk_intr_connect(xtalk_intr, - NULL, - (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t) pcibr_setpciint, - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); - - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 1; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_setpciint: int_addr=0x%lx, *int_addr=0x%lx, " - "pcibr_int_bit=0x%x\n", int_addr, - pcireg_intr_addr_get(pcibr_soft, pcibr_int_bit), - pcibr_int_bit)); - } - - s = pcibr_lock(pcibr_soft); - pcireg_intr_enable_bit_set(pcibr_soft, pcibr_int_bits); - pcireg_tflush_get(pcibr_soft); - pcibr_unlock(pcibr_soft, s); - - return 0; -} - -/*ARGSUSED */ -void -pcibr_intr_disconnect(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - pcibr_intr_wrap_t intr_wrap; - unsigned long s; - - /* Stop calling the function. Now. - */ - *((volatile unsigned *)&pcibr_intr->bi_flags) &= ~PCIIO_INTR_CONNECTED; - pcibr_intr->bi_func = 0; - pcibr_intr->bi_arg = 0; - /* - * For each PCI interrupt line requested, figure - * out which Bridge PCI Interrupt Line it maps - * to, and disconnect the interrupt. - */ - - /* don't disable interrupts for lines that - * are shared between devices. - */ - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if ((pcibr_int_bits & (1 << pcibr_int_bit)) && - (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared)) - pcibr_int_bits &= ~(1 << pcibr_int_bit); - if (!pcibr_int_bits) - return; - - s = pcibr_lock(pcibr_soft); - pcireg_intr_enable_bit_clr(pcibr_soft, pcibr_int_bits); - pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ - pcibr_unlock(pcibr_soft, s); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_intr_disconnect: disabled int_bits=0x%x\n", - pcibr_int_bits)); - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) { - - /* if the interrupt line is now shared, - * do not disconnect it. - */ - if (pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - xtalk_intr_disconnect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_connected = 0; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_intr_disconnect: disconnect int_bits=0x%x\n", - pcibr_int_bits)); - - /* if we are sharing the interrupt line, - * connect us up; this closes the hole - * where the another pcibr_intr_alloc() - * was in progress as we disconnected. - */ - intr_wrap = &pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap; - if (!pcibr_soft->bs_intr[pcibr_int_bit].bsi_pcibr_intr_wrap.iw_shared) - continue; - - pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit = - ((pcibr_soft->bs_busnum << 3) | pcibr_int_bit); - xtalk_intr_connect(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr, - NULL, - (intr_arg_t) intr_wrap, - (xtalk_intr_setfunc_t) pcibr_setpciint, - &pcibr_soft->bs_intr[pcibr_int_bit].bsi_int_bit); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_intr->bi_dev, - "pcibr_intr_disconnect: now-sharing int_bits=0x%x\n", - pcibr_int_bit)); - } -} - -/*ARGSUSED */ -vertex_hdl_t -pcibr_intr_cpu_get(pcibr_intr_t pcibr_intr) -{ - pcibr_soft_t pcibr_soft = pcibr_intr->bi_soft; - unsigned pcibr_int_bits = pcibr_intr->bi_ibits; - unsigned pcibr_int_bit; - - for (pcibr_int_bit = 0; pcibr_int_bit < 8; pcibr_int_bit++) - if (pcibr_int_bits & (1 << pcibr_int_bit)) - return xtalk_intr_cpu_get(pcibr_soft->bs_intr[pcibr_int_bit].bsi_xtalk_intr); - return 0; -} - -/* ===================================================================== - * INTERRUPT HANDLING - */ -void -pcibr_clearwidint(pcibr_soft_t pcibr_soft) -{ - pcireg_intr_dst_set(pcibr_soft, 0); -} - - -void -pcibr_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - - pcibr_soft_t bridge = (pcibr_soft_t)xtalk_intr_sfarg_get(intr); - - pcireg_intr_dst_target_id_set(bridge, targ); - pcireg_intr_dst_addr_set(bridge, addr); - pcireg_intr_host_err_set(bridge, vect); -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c deleted file mode 100644 index 601a81ce8..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_reg.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - - -/* - * Identification Register Access -- Read Only 0000_0000 - */ -static uint64_t -__pcireg_id_get(pic_t *bridge) -{ - return bridge->p_wid_id; -} - -uint64_t -pcireg_bridge_id_get(void *ptr) -{ - return __pcireg_id_get((pic_t *)ptr); -} - -uint64_t -pcireg_id_get(pcibr_soft_t ptr) -{ - return __pcireg_id_get((pic_t *)ptr->bs_base); -} - - - -/* - * Address Bus Side Holding Register Access -- Read Only 0000_0010 - */ -uint64_t -pcireg_bus_err_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_err; -} - - -/* - * Control Register Access -- Read/Write 0000_0020 - */ -static uint64_t -__pcireg_control_get(pic_t *bridge) -{ - return bridge->p_wid_control; -} - -uint64_t -pcireg_bridge_control_get(void *ptr) -{ - return __pcireg_control_get((pic_t *)ptr); -} - -uint64_t -pcireg_control_get(pcibr_soft_t ptr) -{ - return __pcireg_control_get((pic_t *)ptr->bs_base); -} - - -void -pcireg_control_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - /* WAR for PV 439897 & 454474. Add a readback of the control - * register. Lock to protect against MP accesses to this - * register along with other write-only registers (See PVs). - * This register isnt accessed in the "hot path" so the splhi - * shouldn't be a bottleneck - */ - - bridge->p_wid_control = val; - bridge->p_wid_control; /* WAR */ -} - - -void -pcireg_control_bit_clr(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - /* WAR for PV 439897 & 454474. Add a readback of the control - * register. Lock to protect against MP accesses to this - * register along with other write-only registers (See PVs). - * This register isnt accessed in the "hot path" so the splhi - * shouldn't be a bottleneck - */ - - bridge->p_wid_control &= ~bits; - bridge->p_wid_control; /* WAR */ -} - - -void -pcireg_control_bit_set(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - /* WAR for PV 439897 & 454474. Add a readback of the control - * register. Lock to protect against MP accesses to this - * register along with other write-only registers (See PVs). - * This register isnt accessed in the "hot path" so the splhi - * shouldn't be a bottleneck - */ - - bridge->p_wid_control |= bits; - bridge->p_wid_control; /* WAR */ -} - -/* - * Bus Speed (from control register); -- Read Only access 0000_0020 - * 0x00 == 33MHz, 0x01 == 66MHz, 0x10 == 100MHz, 0x11 == 133MHz - */ -uint64_t -pcireg_speed_get(pcibr_soft_t ptr) -{ - uint64_t speedbits; - pic_t *bridge = (pic_t *)ptr->bs_base; - - speedbits = bridge->p_wid_control & PIC_CTRL_PCI_SPEED; - return (speedbits >> 4); -} - -/* - * Bus Mode (ie. PCIX or PCI) (from Status register); 0000_0008 - * 0x0 == PCI, 0x1 == PCI-X - */ -uint64_t -pcireg_mode_get(pcibr_soft_t ptr) -{ - uint64_t pcix_active_bit; - pic_t *bridge = (pic_t *)ptr->bs_base; - - pcix_active_bit = bridge->p_wid_stat & PIC_STAT_PCIX_ACTIVE; - return (pcix_active_bit >> PIC_STAT_PCIX_ACTIVE_SHFT); -} - -void -pcireg_req_timeout_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_wid_req_timeout = val; -} - -/* - * Interrupt Destination Addr Register Access -- Read/Write 0000_0038 - */ - -void -pcireg_intr_dst_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_wid_int = val; -} - -/* - * Intr Destination Addr Reg Access (target_id) -- Read/Write 0000_0038 - */ -uint64_t -pcireg_intr_dst_target_id_get(pcibr_soft_t ptr) -{ - uint64_t tid_bits; - pic_t *bridge = (pic_t *)ptr->bs_base; - - tid_bits = (bridge->p_wid_int & PIC_INTR_DEST_TID); - return (tid_bits >> PIC_INTR_DEST_TID_SHFT); -} - -void -pcireg_intr_dst_target_id_set(pcibr_soft_t ptr, uint64_t target_id) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_wid_int &= ~PIC_INTR_DEST_TID; - bridge->p_wid_int |= - ((target_id << PIC_INTR_DEST_TID_SHFT) & PIC_INTR_DEST_TID); -} - -/* - * Intr Destination Addr Register Access (addr) -- Read/Write 0000_0038 - */ -uint64_t -pcireg_intr_dst_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_int & PIC_XTALK_ADDR_MASK; -} - -void -pcireg_intr_dst_addr_set(pcibr_soft_t ptr, uint64_t addr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_wid_int &= ~PIC_XTALK_ADDR_MASK; - bridge->p_wid_int |= (addr & PIC_XTALK_ADDR_MASK); -} - -/* - * Cmd Word Holding Bus Side Error Register Access -- Read Only 0000_0040 - */ -uint64_t -pcireg_cmdword_err_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_err_cmdword; -} - -/* - * PCI/PCIX Target Flush Register Access -- Read Only 0000_0050 - */ -uint64_t -pcireg_tflush_get(pcibr_soft_t ptr) -{ - uint64_t ret = 0; - pic_t *bridge = (pic_t *)ptr->bs_base; - - ret = bridge->p_wid_tflush; - - /* Read of the Targer Flush should always return zero */ - ASSERT_ALWAYS(ret == 0); - return ret; -} - -/* - * Cmd Word Holding Link Side Error Register Access -- Read Only 0000_0058 - */ -uint64_t -pcireg_linkside_err_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_aux_err; -} - -/* - * PCI Response Buffer Address Holding Register -- Read Only 0000_0068 - */ -uint64_t -pcireg_resp_err_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_resp; -} - -/* - * PCI Resp Buffer Address Holding Reg (Address) -- Read Only 0000_0068 - */ -uint64_t -pcireg_resp_err_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_resp & PIC_RSP_BUF_ADDR; -} - -/* - * PCI Resp Buffer Address Holding Register (Buffer)-- Read Only 0000_0068 - */ -uint64_t -pcireg_resp_err_buf_get(pcibr_soft_t ptr) -{ - uint64_t bufnum_bits; - pic_t *bridge = (pic_t *)ptr->bs_base; - - bufnum_bits = (bridge->p_wid_resp_upper & PIC_RSP_BUF_NUM); - return (bufnum_bits >> PIC_RSP_BUF_NUM_SHFT); -} - -/* - * PCI Resp Buffer Address Holding Register (Device)-- Read Only 0000_0068 - */ -uint64_t -pcireg_resp_err_dev_get(pcibr_soft_t ptr) -{ - uint64_t devnum_bits; - pic_t *bridge = (pic_t *)ptr->bs_base; - - devnum_bits = (bridge->p_wid_resp_upper & PIC_RSP_BUF_DEV_NUM); - return (devnum_bits >> PIC_RSP_BUF_DEV_NUM_SHFT); -} - -/* - * Address Holding Register Link Side Errors -- Read Only 0000_0078 - */ -uint64_t -pcireg_linkside_err_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_wid_addr_lkerr; -} - -void -pcireg_dirmap_wid_set(pcibr_soft_t ptr, uint64_t target) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_dir_map &= ~PIC_DIRMAP_WID; - bridge->p_dir_map |= - ((target << PIC_DIRMAP_WID_SHFT) & PIC_DIRMAP_WID); -} - -void -pcireg_dirmap_diroff_set(pcibr_soft_t ptr, uint64_t dir_off) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_dir_map &= ~PIC_DIRMAP_DIROFF; - bridge->p_dir_map |= (dir_off & PIC_DIRMAP_DIROFF); -} - -void -pcireg_dirmap_add512_set(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_dir_map |= PIC_DIRMAP_ADD512; -} - -void -pcireg_dirmap_add512_clr(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_dir_map &= ~PIC_DIRMAP_ADD512; -} - -/* - * PCI Page Map Fault Address Register Access -- Read Only 0000_0090 - */ -uint64_t -pcireg_map_fault_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_map_fault; -} - -/* - * Arbitration Register Access -- Read/Write 0000_00A0 - */ -uint64_t -pcireg_arbitration_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_arb; -} - -void -pcireg_arbitration_bit_set(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_arb |= bits; -} - -/* - * Internal Ram Parity Error Register Access -- Read Only 0000_00B0 - */ -uint64_t -pcireg_parity_err_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_ate_parity_err; -} - -/* - * Type 1 Configuration Register Access -- Read/Write 0000_00C8 - */ -void -pcireg_type1_cntr_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_pci_cfg = val; -} - -/* - * PCI Bus Error Lower Addr Holding Reg Access -- Read Only 0000_00D8 - */ -uint64_t -pcireg_pci_bus_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pci_err; -} - -/* - * PCI Bus Error Addr Holding Reg Access (Address) -- Read Only 0000_00D8 - */ -uint64_t -pcireg_pci_bus_addr_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pci_err & PIC_XTALK_ADDR_MASK; -} - -/* - * Interrupt Status Register Access -- Read Only 0000_0100 - */ -uint64_t -pcireg_intr_status_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_int_status; -} - -/* - * Interrupt Enable Register Access -- Read/Write 0000_0108 - */ -uint64_t -pcireg_intr_enable_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_int_enable; -} - -void -pcireg_intr_enable_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_enable = val; -} - -void -pcireg_intr_enable_bit_clr(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_enable &= ~bits; -} - -void -pcireg_intr_enable_bit_set(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_enable |= bits; -} - -/* - * Interrupt Reset Register Access -- Write Only 0000_0110 - */ -void -pcireg_intr_reset_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_rst_stat = val; -} - -void -pcireg_intr_mode_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_mode = val; -} - -void -pcireg_intr_device_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_device = val; -} - -static void -__pcireg_intr_device_bit_set(pic_t *bridge, uint64_t bits) -{ - bridge->p_int_device |= bits; -} - -void -pcireg_bridge_intr_device_bit_set(void *ptr, uint64_t bits) -{ - __pcireg_intr_device_bit_set((pic_t *)ptr, bits); -} - -void -pcireg_intr_device_bit_set(pcibr_soft_t ptr, uint64_t bits) -{ - __pcireg_intr_device_bit_set((pic_t *)ptr->bs_base, bits); -} - -void -pcireg_intr_device_bit_clr(pcibr_soft_t ptr, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_device &= ~bits; -} - -/* - * Host Error Interrupt Field Register Access -- Read/Write 0000_0128 - */ -void -pcireg_intr_host_err_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_int_host_err = val; -} - -/* - * Interrupt Host Address Register -- Read/Write 0000_0130 - 0000_0168 - */ -uint64_t -pcireg_intr_addr_get(pcibr_soft_t ptr, int int_n) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_int_addr[int_n]; -} - -static void -__pcireg_intr_addr_set(pic_t *bridge, int int_n, uint64_t val) -{ - bridge->p_int_addr[int_n] = val; -} - -void -pcireg_bridge_intr_addr_set(void *ptr, int int_n, uint64_t val) -{ - __pcireg_intr_addr_set((pic_t *)ptr, int_n, val); -} - -void -pcireg_intr_addr_set(pcibr_soft_t ptr, int int_n, uint64_t val) -{ - __pcireg_intr_addr_set((pic_t *)ptr->bs_base, int_n, val); -} - -void * -pcireg_intr_addr_addr(pcibr_soft_t ptr, int int_n) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return (void *)&(bridge->p_int_addr[int_n]); -} - -static void -__pcireg_intr_addr_vect_set(pic_t *bridge, int int_n, uint64_t vect) -{ - bridge->p_int_addr[int_n] &= ~PIC_HOST_INTR_FLD; - bridge->p_int_addr[int_n] |= - ((vect << PIC_HOST_INTR_FLD_SHFT) & PIC_HOST_INTR_FLD); -} - -void -pcireg_bridge_intr_addr_vect_set(void *ptr, int int_n, uint64_t vect) -{ - __pcireg_intr_addr_vect_set((pic_t *)ptr, int_n, vect); -} - -void -pcireg_intr_addr_vect_set(pcibr_soft_t ptr, int int_n, uint64_t vect) -{ - __pcireg_intr_addr_vect_set((pic_t *)ptr->bs_base, int_n, vect); -} - - - -/* - * Intr Host Address Register (int_addr) -- Read/Write 0000_0130 - 0000_0168 - */ -static void -__pcireg_intr_addr_addr_set(pic_t *bridge, int int_n, uint64_t addr) -{ - bridge->p_int_addr[int_n] &= ~PIC_HOST_INTR_ADDR; - bridge->p_int_addr[int_n] |= (addr & PIC_HOST_INTR_ADDR); -} - -void -pcireg_bridge_intr_addr_addr_set(void *ptr, int int_n, uint64_t addr) -{ - __pcireg_intr_addr_addr_set((pic_t *)ptr, int_n, addr); -} - -void -pcireg_intr_addr_addr_set(pcibr_soft_t ptr, int int_n, uint64_t addr) -{ - __pcireg_intr_addr_addr_set((pic_t *)ptr->bs_base, int_n, addr); -} - -/* - * Multiple Interrupt Register Access -- Read Only 0000_0178 - */ -uint64_t -pcireg_intr_multiple_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_mult_int; -} - -/* - * Force Always Intr Register Access -- Write Only 0000_0180 - 0000_01B8 - */ -static void * -__pcireg_force_always_addr_get(pic_t *bridge, int int_n) -{ - return (void *)&(bridge->p_force_always[int_n]); -} - -void * -pcireg_bridge_force_always_addr_get(void *ptr, int int_n) -{ - return __pcireg_force_always_addr_get((pic_t *)ptr, int_n); -} - -void * -pcireg_force_always_addr_get(pcibr_soft_t ptr, int int_n) -{ - return __pcireg_force_always_addr_get((pic_t *)ptr->bs_base, int_n); -} - -/* - * Force Interrupt Register Access -- Write Only 0000_01C0 - 0000_01F8 - */ -void -pcireg_force_intr_set(pcibr_soft_t ptr, int int_n) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_force_pin[int_n] = 1; -} - -/* - * Device(x) Register Access -- Read/Write 0000_0200 - 0000_0218 - */ -uint64_t -pcireg_device_get(pcibr_soft_t ptr, int device) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - ASSERT_ALWAYS((device >= 0) && (device <= 3)); - return bridge->p_device[device]; -} - -void -pcireg_device_set(pcibr_soft_t ptr, int device, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - ASSERT_ALWAYS((device >= 0) && (device <= 3)); - bridge->p_device[device] = val; -} - -/* - * Device(x) Write Buffer Flush Reg Access -- Read Only 0000_0240 - 0000_0258 - */ -uint64_t -pcireg_wrb_flush_get(pcibr_soft_t ptr, int device) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - uint64_t ret = 0; - - ASSERT_ALWAYS((device >= 0) && (device <= 3)); - ret = bridge->p_wr_req_buf[device]; - - /* Read of the Write Buffer Flush should always return zero */ - ASSERT_ALWAYS(ret == 0); - return ret; -} - -/* - * Even/Odd RRB Register Access -- Read/Write 0000_0280 - 0000_0288 - */ -uint64_t -pcireg_rrb_get(pcibr_soft_t ptr, int even_odd) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_rrb_map[even_odd]; -} - -void -pcireg_rrb_set(pcibr_soft_t ptr, int even_odd, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_rrb_map[even_odd] = val; -} - -void -pcireg_rrb_bit_set(pcibr_soft_t ptr, int even_odd, uint64_t bits) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_rrb_map[even_odd] |= bits; -} - -/* - * RRB Status Register Access -- Read Only 0000_0290 - */ -uint64_t -pcireg_rrb_status_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_resp_status; -} - -/* - * RRB Clear Register Access -- Write Only 0000_0298 - */ -void -pcireg_rrb_clear_set(pcibr_soft_t ptr, uint64_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - bridge->p_resp_clear = val; -} - -/* - * PCIX Bus Error Address Register Access -- Read Only 0000_0600 - */ -uint64_t -pcireg_pcix_bus_err_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_bus_err_addr; -} - -/* - * PCIX Bus Error Attribute Register Access -- Read Only 0000_0608 - */ -uint64_t -pcireg_pcix_bus_err_attr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_bus_err_attr; -} - -/* - * PCIX Bus Error Data Register Access -- Read Only 0000_0610 - */ -uint64_t -pcireg_pcix_bus_err_data_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_bus_err_data; -} - -/* - * PCIX PIO Split Request Address Register Access -- Read Only 0000_0618 - */ -uint64_t -pcireg_pcix_pio_split_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_pio_split_addr; -} - -/* - * PCIX PIO Split Request Attribute Register Access -- Read Only 0000_0620 - */ -uint64_t -pcireg_pcix_pio_split_attr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_pio_split_attr; -} - -/* - * PCIX DMA Request Error Attribute Register Access -- Read Only 0000_0628 - */ -uint64_t -pcireg_pcix_req_err_attr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_dma_req_err_attr; -} - -/* - * PCIX DMA Request Error Address Register Access -- Read Only 0000_0630 - */ -uint64_t -pcireg_pcix_req_err_addr_get(pcibr_soft_t ptr) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - return bridge->p_pcix_dma_req_err_addr; -} - -/* - * Type 0 Configuration Space Access -- Read/Write - */ -cfg_p -pcireg_type0_cfg_addr(pcibr_soft_t ptr, uint8_t slot, uint8_t func, int off) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - /* Type 0 Config space accesses on PIC are 1-4, not 0-3 since - * it is a PCIX Bridge. See sys/PCI/pic.h for explanation. - */ - slot++; - ASSERT_ALWAYS(((int) slot >= 1) && ((int) slot <= 4)); - return &(bridge->p_type0_cfg_dev[slot].f[func].l[(off / 4)]); -} - -/* - * Type 1 Configuration Space Access -- Read/Write - */ -cfg_p -pcireg_type1_cfg_addr(pcibr_soft_t ptr, uint8_t func, int offset) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - /* - * Return a config space address for the given slot/func/offset. - * Note the returned ptr is a 32bit word (ie. cfg_p) aligned ptr - * pointing to the 32bit word that contains the "offset" byte. - */ - return &(bridge->p_type1_cfg.f[func].l[(offset / 4)]); -} - -/* - * Internal ATE SSRAM Access -- Read/Write - */ -bridge_ate_t -pcireg_int_ate_get(pcibr_soft_t ptr, int ate_index) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); - return bridge->p_int_ate_ram[ate_index]; -} - -void -pcireg_int_ate_set(pcibr_soft_t ptr, int ate_index, bridge_ate_t val) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); - bridge->p_int_ate_ram[ate_index] = (picate_t) val; -} - -bridge_ate_p -pcireg_int_ate_addr(pcibr_soft_t ptr, int ate_index) -{ - pic_t *bridge = (pic_t *)ptr->bs_base; - - ASSERT_ALWAYS((ate_index >= 0) && (ate_index <= 1024)); - return &(bridge->p_int_ate_ram[ate_index]); -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c deleted file mode 100644 index 6958e5547..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_rrb.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -void pcibr_rrb_alloc_init(pcibr_soft_t, int, int, int); -void pcibr_rrb_alloc_more(pcibr_soft_t, int, int, int); - -int pcibr_wrb_flush(vertex_hdl_t); -int pcibr_rrb_alloc(vertex_hdl_t, int *, int *); -int pcibr_rrb_check(vertex_hdl_t, int *, int *, int *, int *); -int pcibr_alloc_all_rrbs(vertex_hdl_t, int, int, int, int, - int, int, int, int, int); -void pcibr_rrb_flush(vertex_hdl_t); -int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); - -void pcibr_rrb_debug(char *, pcibr_soft_t); - - -/* - * RRB Management - * - * All the do_pcibr_rrb_ routines manipulate the Read Response Buffer (rrb) - * registers within the Bridge. Two 32 registers (b_rrb_map[2] also known - * as the b_even_resp & b_odd_resp registers) are used to allocate the 16 - * rrbs to devices. The b_even_resp register represents even num devices, - * and b_odd_resp represent odd number devices. Each rrb is represented by - * 4-bits within a register. - * BRIDGE & XBRIDGE: 1 enable bit, 1 virtual channel bit, 2 device bits - * PIC: 1 enable bit, 2 virtual channel bits, 1 device bit - * PIC has 4 devices per bus, and 4 virtual channels (1 normal & 3 virtual) - * per device. BRIDGE & XBRIDGE have 8 devices per bus and 2 virtual - * channels (1 normal & 1 virtual) per device. See the BRIDGE and PIC ASIC - * Programmers Reference guides for more information. - */ - -#define RRB_MASK (0xf) /* mask a single rrb within reg */ -#define RRB_SIZE (4) /* sizeof rrb within reg (bits) */ - -#define RRB_ENABLE_BIT (0x8) /* [BRIDGE | PIC]_RRB_EN */ -#define NUM_PDEV_BITS (1) -#define NUMBER_VCHANNELS (4) -#define SLOT_2_PDEV(slot) ((slot) >> 1) -#define SLOT_2_RRB_REG(slot) ((slot) & 0x1) - -#define RRB_VALID(rrb) (0x00010000 << (rrb)) -#define RRB_INUSE(rrb) (0x00000001 << (rrb)) -#define RRB_CLEAR(rrb) (0x00000001 << (rrb)) - -/* validate that the slot and virtual channel are valid */ -#define VALIDATE_SLOT_n_VCHAN(s, v) \ - (((((s) != PCIIO_SLOT_NONE) && ((s) <= (pciio_slot_t)3)) && \ - (((v) >= 0) && ((v) <= 3))) ? 1 : 0) - -/* - * Count how many RRBs are marked valid for the specified PCI slot - * and virtual channel. Return the count. - */ -static int -do_pcibr_rrb_count_valid(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - int vchan) -{ - uint64_t tmp; - uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; - int rrb_index, cnt=0; - - if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { - printk(KERN_WARNING "do_pcibr_rrb_count_valid() invalid slot/vchan [%d/%d]\n", slot, vchan); - return 0; - } - - enable_bit = RRB_ENABLE_BIT; - vchan_bits = vchan << NUM_PDEV_BITS; - pdev_bits = SLOT_2_PDEV(slot); - rrb_bits = enable_bit | vchan_bits | pdev_bits; - - tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); - - for (rrb_index = 0; rrb_index < 8; rrb_index++) { - if ((tmp & RRB_MASK) == rrb_bits) - cnt++; - tmp = (tmp >> RRB_SIZE); - } - return cnt; -} - - -/* - * Count how many RRBs are available to be allocated to the specified - * slot. Return the count. - */ -static int -do_pcibr_rrb_count_avail(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - uint64_t tmp; - uint16_t enable_bit; - int rrb_index, cnt=0; - - if (!VALIDATE_SLOT_n_VCHAN(slot, 0)) { - printk(KERN_WARNING "do_pcibr_rrb_count_avail() invalid slot/vchan"); - return 0; - } - - enable_bit = RRB_ENABLE_BIT; - - tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); - - for (rrb_index = 0; rrb_index < 8; rrb_index++) { - if ((tmp & enable_bit) != enable_bit) - cnt++; - tmp = (tmp >> RRB_SIZE); - } - return cnt; -} - - -/* - * Allocate some additional RRBs for the specified slot and the specified - * virtual channel. Returns -1 if there were insufficient free RRBs to - * satisfy the request, or 0 if the request was fulfilled. - * - * Note that if a request can be partially filled, it will be, even if - * we return failure. - */ -static int -do_pcibr_rrb_alloc(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - int vchan, - int more) -{ - uint64_t reg, tmp = 0; - uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; - int rrb_index; - - if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { - printk(KERN_WARNING "do_pcibr_rrb_alloc() invalid slot/vchan"); - return -1; - } - - enable_bit = RRB_ENABLE_BIT; - vchan_bits = vchan << NUM_PDEV_BITS; - pdev_bits = SLOT_2_PDEV(slot); - rrb_bits = enable_bit | vchan_bits | pdev_bits; - - reg = tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); - - for (rrb_index = 0; ((rrb_index < 8) && (more > 0)); rrb_index++) { - if ((tmp & enable_bit) != enable_bit) { - /* clear the rrb and OR in the new rrb into 'reg' */ - reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index)); - reg = reg | (rrb_bits << (RRB_SIZE * rrb_index)); - more--; - } - tmp = (tmp >> RRB_SIZE); - } - - pcireg_rrb_set(pcibr_soft, SLOT_2_RRB_REG(slot), reg); - return (more ? -1 : 0); -} - -/* - * Wait for the the specified rrb to have no outstanding XIO pkts - * and for all data to be drained. Mark the rrb as no longer being - * valid. - */ -static void -do_pcibr_rrb_clear(pcibr_soft_t pcibr_soft, int rrb) -{ - uint64_t status; - - /* bridge_lock must be held; this RRB must be disabled. */ - - /* wait until RRB has no outstanduing XIO packets. */ - status = pcireg_rrb_status_get(pcibr_soft); - while (status & RRB_INUSE(rrb)) { - status = pcireg_rrb_status_get(pcibr_soft); - } - - /* if the RRB has data, drain it. */ - if (status & RRB_VALID(rrb)) { - pcireg_rrb_clear_set(pcibr_soft, RRB_CLEAR(rrb)); - - /* wait until RRB is no longer valid. */ - status = pcireg_rrb_status_get(pcibr_soft); - while (status & RRB_VALID(rrb)) { - status = pcireg_rrb_status_get(pcibr_soft); - } - } -} - - -/* - * Release some of the RRBs that have been allocated for the specified - * slot. Returns zero for success, or negative if it was unable to free - * that many RRBs. - * - * Note that if a request can be partially fulfilled, it will be, even - * if we return failure. - */ -static int -do_pcibr_rrb_free(pcibr_soft_t pcibr_soft, - pciio_slot_t slot, - int vchan, - int less) -{ - uint64_t reg, tmp = 0, clr = 0; - uint16_t enable_bit, vchan_bits, pdev_bits, rrb_bits; - int rrb_index; - - if (!VALIDATE_SLOT_n_VCHAN(slot, vchan)) { - printk(KERN_WARNING "do_pcibr_rrb_free() invalid slot/vchan"); - return -1; - } - - enable_bit = RRB_ENABLE_BIT; - vchan_bits = vchan << NUM_PDEV_BITS; - pdev_bits = SLOT_2_PDEV(slot); - rrb_bits = enable_bit | vchan_bits | pdev_bits; - - reg = tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); - - for (rrb_index = 0; ((rrb_index < 8) && (less > 0)); rrb_index++) { - if ((tmp & RRB_MASK) == rrb_bits) { - /* - * the old do_pcibr_rrb_free() code only clears the enable bit - * but I say we should clear the whole rrb (ie): - * reg = reg & ~(RRB_MASK << (RRB_SIZE * rrb_index)); - * But to be compatible with old code we'll only clear enable. - */ - reg = reg & ~(RRB_ENABLE_BIT << (RRB_SIZE * rrb_index)); - clr = clr | (enable_bit << (RRB_SIZE * rrb_index)); - less--; - } - tmp = (tmp >> RRB_SIZE); - } - - pcireg_rrb_set(pcibr_soft, SLOT_2_RRB_REG(slot), reg); - - /* call do_pcibr_rrb_clear() for all the rrbs we've freed */ - for (rrb_index = 0; rrb_index < 8; rrb_index++) { - int evn_odd = SLOT_2_RRB_REG(slot); - if (clr & (enable_bit << (RRB_SIZE * rrb_index))) - do_pcibr_rrb_clear(pcibr_soft, (2 * rrb_index) + evn_odd); - } - - return (less ? -1 : 0); -} - -/* - * Flush the specified rrb by calling do_pcibr_rrb_clear(). This - * routine is just a wrapper to make sure the rrb is disabled - * before calling do_pcibr_rrb_clear(). - */ -static void -do_pcibr_rrb_flush(pcibr_soft_t pcibr_soft, int rrbn) -{ - uint64_t rrbv; - int shft = (RRB_SIZE * (rrbn >> 1)); - uint64_t ebit = RRB_ENABLE_BIT << shft; - - rrbv = pcireg_rrb_get(pcibr_soft, (rrbn & 1)); - if (rrbv & ebit) { - pcireg_rrb_set(pcibr_soft, (rrbn & 1), (rrbv & ~ebit)); - } - - do_pcibr_rrb_clear(pcibr_soft, rrbn); - - if (rrbv & ebit) { - pcireg_rrb_set(pcibr_soft, (rrbn & 1), rrbv); - } -} - -/* - * free all the rrbs (both the normal and virtual channels) for the - * specified slot. - */ -void -do_pcibr_rrb_free_all(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - int vchan; - int vchan_total = NUMBER_VCHANNELS; - - /* pretend we own all 8 rrbs and just ignore the return value */ - for (vchan = 0; vchan < vchan_total; vchan++) { - do_pcibr_rrb_free(pcibr_soft, slot, vchan, 8); - pcibr_soft->bs_rrb_valid[slot][vchan] = 0; - } -} - - -/* - * Initialize a slot with a given number of RRBs. (this routine - * will also give back RRBs if the slot has more than we want). - */ -void -pcibr_rrb_alloc_init(pcibr_soft_t pcibr_soft, - int slot, - int vchan, - int init_rrbs) -{ - int had = pcibr_soft->bs_rrb_valid[slot][vchan]; - int have = had; - int added = 0; - - for (added = 0; have < init_rrbs; ++added, ++have) { - if (pcibr_soft->bs_rrb_res[slot] > 0) - pcibr_soft->bs_rrb_res[slot]--; - else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) - pcibr_soft->bs_rrb_avail[slot & 1]--; - else - break; - if (do_pcibr_rrb_alloc(pcibr_soft, slot, vchan, 1) < 0) - break; - - pcibr_soft->bs_rrb_valid[slot][vchan]++; - } - - /* Free any extra RRBs that the slot may have allocated to it */ - while (have > init_rrbs) { - pcibr_soft->bs_rrb_avail[slot & 1]++; - pcibr_soft->bs_rrb_valid[slot][vchan]--; - do_pcibr_rrb_free(pcibr_soft, slot, vchan, 1); - added--; - have--; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "pcibr_rrb_alloc_init: had %d, added/removed %d, " - "(of requested %d) RRBs " - "to slot %d, vchan %d\n", had, added, init_rrbs, - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); - - pcibr_rrb_debug("pcibr_rrb_alloc_init", pcibr_soft); -} - - -/* - * Allocate more RRBs to a given slot (if the RRBs are available). - */ -void -pcibr_rrb_alloc_more(pcibr_soft_t pcibr_soft, - int slot, - int vchan, - int more_rrbs) -{ - int added; - - for (added = 0; added < more_rrbs; ++added) { - if (pcibr_soft->bs_rrb_res[slot] > 0) - pcibr_soft->bs_rrb_res[slot]--; - else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) - pcibr_soft->bs_rrb_avail[slot & 1]--; - else - break; - if (do_pcibr_rrb_alloc(pcibr_soft, slot, vchan, 1) < 0) - break; - - pcibr_soft->bs_rrb_valid[slot][vchan]++; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "pcibr_rrb_alloc_more: added %d (of %d requested) RRBs " - "to slot %d, vchan %d\n", added, more_rrbs, - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); - - pcibr_rrb_debug("pcibr_rrb_alloc_more", pcibr_soft); -} - - -/* - * Flush all the rrb's assigned to the specified connection point. - */ -void -pcibr_rrb_flush(vertex_hdl_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); - pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - - uint64_t tmp; - uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask; - int rrb_index; - unsigned long s; - - enable_bit = RRB_ENABLE_BIT; - pdev_bits = SLOT_2_PDEV(slot); - rrb_bits = enable_bit | pdev_bits; - rrb_mask = enable_bit | ((NUM_PDEV_BITS << 1) - 1); - - tmp = pcireg_rrb_get(pcibr_soft, SLOT_2_RRB_REG(slot)); - - s = pcibr_lock(pcibr_soft); - for (rrb_index = 0; rrb_index < 8; rrb_index++) { - int evn_odd = SLOT_2_RRB_REG(slot); - if ((tmp & rrb_mask) == rrb_bits) - do_pcibr_rrb_flush(pcibr_soft, (2 * rrb_index) + evn_odd); - tmp = (tmp >> RRB_SIZE); - } - pcibr_unlock(pcibr_soft, s); -} - - -/* - * Device driver interface to flush the write buffers for a specified - * device hanging off the bridge. - */ -int -pcibr_wrb_flush(vertex_hdl_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - - pcireg_wrb_flush_get(pcibr_soft, pciio_slot); - - return 0; -} - -/* - * Device driver interface to request RRBs for a specified device - * hanging off a Bridge. The driver requests the total number of - * RRBs it would like for the normal channel (vchan0) and for the - * "virtual channel" (vchan1). The actual number allocated to each - * channel is returned. - * - * If we cannot allocate at least one RRB to a channel that needs - * at least one, return -1 (failure). Otherwise, satisfy the request - * as best we can and return 0. - */ -int -pcibr_rrb_alloc(vertex_hdl_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); - pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); - int desired_vchan0; - int desired_vchan1; - int orig_vchan0; - int orig_vchan1; - int delta_vchan0; - int delta_vchan1; - int final_vchan0; - int final_vchan1; - int avail_rrbs; - int res_rrbs; - int vchan_total; - int vchan; - unsigned long s; - int error; - - /* - * TBD: temper request with admin info about RRB allocation, - * and according to demand from other devices on this Bridge. - * - * One way of doing this would be to allocate two RRBs - * for each device on the bus, before any drivers start - * asking for extras. This has the weakness that one - * driver might not give back an "extra" RRB until after - * another driver has already failed to get one that - * it wanted. - */ - - s = pcibr_lock(pcibr_soft); - - vchan_total = NUMBER_VCHANNELS; - - /* Save the boot-time RRB configuration for this slot */ - if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) { - for (vchan = 0; vchan < vchan_total; vchan++) - pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] = - pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; - pcibr_soft->bs_rrb_res_dflt[pciio_slot] = - pcibr_soft->bs_rrb_res[pciio_slot]; - - } - - /* How many RRBs do we own? */ - orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0]; - orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1]; - - /* How many RRBs do we want? */ - desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; - desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; - - /* How many RRBs are free? */ - avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot]; - - /* Figure desired deltas */ - delta_vchan0 = desired_vchan0 - orig_vchan0; - delta_vchan1 = desired_vchan1 - orig_vchan1; - - /* Trim back deltas to something - * that we can actually meet, by - * decreasing the ending allocation - * for whichever channel wants - * more RRBs. If both want the same - * number, cut the second channel. - * NOTE: do not change the allocation for - * a channel that was passed as NULL. - */ - while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { - if (count_vchan0 && - (!count_vchan1 || - ((orig_vchan0 + delta_vchan0) > - (orig_vchan1 + delta_vchan1)))) - delta_vchan0--; - else - delta_vchan1--; - } - - /* Figure final RRB allocations - */ - final_vchan0 = orig_vchan0 + delta_vchan0; - final_vchan1 = orig_vchan1 + delta_vchan1; - - /* If either channel wants RRBs but our actions - * would leave it with none, declare an error, - * but DO NOT change any RRB allocations. - */ - if ((desired_vchan0 && !final_vchan0) || - (desired_vchan1 && !final_vchan1)) { - - error = -1; - - } else { - - /* Commit the allocations: free, then alloc. - */ - if (delta_vchan0 < 0) - do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN0, -delta_vchan0); - if (delta_vchan1 < 0) - do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN1, -delta_vchan1); - - if (delta_vchan0 > 0) - do_pcibr_rrb_alloc(pcibr_soft, pciio_slot, VCHAN0, delta_vchan0); - if (delta_vchan1 > 0) - do_pcibr_rrb_alloc(pcibr_soft, pciio_slot, VCHAN1, delta_vchan1); - - /* Return final values to caller. - */ - if (count_vchan0) - *count_vchan0 = final_vchan0; - if (count_vchan1) - *count_vchan1 = final_vchan1; - - /* prevent automatic changes to this slot's RRBs - */ - pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; - - /* Track the actual allocations, release - * any further reservations, and update the - * number of available RRBs. - */ - - pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0; - pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - + pcibr_soft->bs_rrb_res[pciio_slot] - - delta_vchan0 - - delta_vchan1; - pcibr_soft->bs_rrb_res[pciio_slot] = 0; - - /* - * Reserve enough RRBs so this slot's RRB configuration can be - * reset to its boot-time default following a hot-plug shut-down - */ - res_rrbs = (pcibr_soft->bs_rrb_res_dflt[pciio_slot] - - pcibr_soft->bs_rrb_res[pciio_slot]); - for (vchan = 0; vchan < vchan_total; vchan++) { - res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] - - pcibr_soft->bs_rrb_valid[pciio_slot][vchan]); - } - - if (res_rrbs > 0) { - pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs; - pcibr_soft->bs_rrb_avail[pciio_slot & 1] = - pcibr_soft->bs_rrb_avail[pciio_slot & 1] - - res_rrbs; - } - - pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft); - - error = 0; - } - - pcibr_unlock(pcibr_soft, s); - - return error; -} - -/* - * Device driver interface to check the current state - * of the RRB allocations. - * - * pconn_vhdl is your PCI connection point (specifies which - * PCI bus and which slot). - * - * count_vchan0 points to where to return the number of RRBs - * assigned to the primary DMA channel, used by all DMA - * that does not explicitly ask for the alternate virtual - * channel. - * - * count_vchan1 points to where to return the number of RRBs - * assigned to the secondary DMA channel, used when - * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. - * - * count_reserved points to where to return the number of RRBs - * that have been automatically reserved for your device at - * startup, but which have not been assigned to a - * channel. RRBs must be assigned to a channel to be used; - * this can be done either with an explicit pcibr_rrb_alloc - * call, or automatically by the infrastructure when a DMA - * translation is constructed. Any call to pcibr_rrb_alloc - * will release any unassigned reserved RRBs back to the - * free pool. - * - * count_pool points to where to return the number of RRBs - * that are currently unassigned and unreserved. This - * number can (and will) change as other drivers make calls - * to pcibr_rrb_alloc, or automatically allocate RRBs for - * DMA beyond their initial reservation. - * - * NULL may be passed for any of the return value pointers - * the caller is not interested in. - * - * The return value is "0" if all went well, or "-1" if - * there is a problem. Additionally, if the wrong vertex - * is passed in, one of the subsidiary support functions - * could panic with a "bad pciio fingerprint." - */ - -int -pcibr_rrb_check(vertex_hdl_t pconn_vhdl, - int *count_vchan0, - int *count_vchan1, - int *count_reserved, - int *count_pool) -{ - pciio_info_t pciio_info; - pciio_slot_t pciio_slot; - pcibr_soft_t pcibr_soft; - unsigned long s; - int error = -1; - - if ((pciio_info = pciio_info_get(pconn_vhdl)) && - (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && - ((pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) { - - s = pcibr_lock(pcibr_soft); - - if (count_vchan0) - *count_vchan0 = - pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0]; - - if (count_vchan1) - *count_vchan1 = - pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1]; - - if (count_reserved) - *count_reserved = - pcibr_soft->bs_rrb_res[pciio_slot]; - - if (count_pool) - *count_pool = - pcibr_soft->bs_rrb_avail[pciio_slot & 1]; - - error = 0; - - pcibr_unlock(pcibr_soft, s); - } - return error; -} - -/* - * pcibr_slot_initial_rrb_alloc - * Allocate a default number of rrbs for this slot on - * the two channels. This is dictated by the rrb allocation - * strategy routine defined per platform. - */ - -int -pcibr_slot_initial_rrb_alloc(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int vchan_total; - int vchan; - int chan[4]; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - /* How many RRBs are on this slot? */ - vchan_total = NUMBER_VCHANNELS; - for (vchan = 0; vchan < vchan_total; vchan++) - chan[vchan] = do_pcibr_rrb_count_valid(pcibr_soft, slot, vchan); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl, - "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3])); - - /* Do we really need any? - */ - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - pcibr_info = pcibr_infoh[0]; - /* - * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): - * Don't free RRBs we allocated to device[2|3]--vchan3 as - * a WAR to those PVs mentioned above. In pcibr_attach2 - * we allocate RRB0,8,1,9 to device[2|3]--vchan3. - */ - if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && - (slot == 2 || slot == 3) && - (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - - for (vchan = 0; vchan < 2; vchan++) { - do_pcibr_rrb_free(pcibr_soft, slot, vchan, 8); - pcibr_soft->bs_rrb_valid[slot][vchan] = 0; - } - - pcibr_soft->bs_rrb_valid[slot][3] = chan[3]; - - return -ENODEV; - } - - if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && - !pcibr_soft->bs_slot[slot].has_host) { - do_pcibr_rrb_free_all(pcibr_soft, slot); - - /* Reserve RRBs for this empty slot for hot-plug */ - for (vchan = 0; vchan < vchan_total; vchan++) - pcibr_soft->bs_rrb_valid[slot][vchan] = 0; - - return -ENODEV; - } - - for (vchan = 0; vchan < vchan_total; vchan++) - pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan]; - - return 0; -} - - -/* - * pcibr_initial_rrb - * Assign an equal total number of RRBs to all candidate slots, - * where the total is the sum of the number of RRBs assigned to - * the normal channel, the number of RRBs assigned to the virtual - * channels, and the number of RRBs assigned as reserved. - * - * A candidate slot is any existing (populated or empty) slot. - * Empty SN1 slots need RRBs to support hot-plug operations. - */ - -int -pcibr_initial_rrb(vertex_hdl_t pcibr_vhdl, - pciio_slot_t first, pciio_slot_t last) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot; - int rrb_total; - int vchan_total; - int vchan; - int have[2][3]; - int res[2]; - int eo; - - have[0][0] = have[0][1] = have[0][2] = 0; - have[1][0] = have[1][1] = have[1][2] = 0; - res[0] = res[1] = 0; - - vchan_total = NUMBER_VCHANNELS; - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Initial RRB management; give back RRBs in all non-existent slots */ - pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); - - /* Base calculations only on existing slots */ - if ((slot >= first) && (slot <= last)) { - rrb_total = 0; - for (vchan = 0; vchan < vchan_total; vchan++) - rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan]; - - if (rrb_total < 3) - have[slot & 1][rrb_total]++; - } - } - - /* Initialize even/odd slot available RRB counts */ - pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(pcibr_soft, 0); - pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(pcibr_soft, 1); - - /* - * Calculate reserved RRBs for slots based on current RRB usage - */ - for (eo = 0; eo < 2; eo++) { - if ((3 * have[eo][0] + 2 * have[eo][1] + have[eo][2]) <= pcibr_soft->bs_rrb_avail[eo]) - res[eo] = 3; - else if ((2 * have[eo][0] + have[eo][1]) <= pcibr_soft->bs_rrb_avail[eo]) - res[eo] = 2; - else if (have[eo][0] <= pcibr_soft->bs_rrb_avail[eo]) - res[eo] = 1; - else - res[eo] = 0; - - } - - /* Assign reserved RRBs to existing slots */ - for (slot = first; slot <= last; ++slot) { - int r; - - if (pcibr_soft->bs_unused_slot & (1 << slot)) - continue; - - rrb_total = 0; - for (vchan = 0; vchan < vchan_total; vchan++) - rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan]; - - r = res[slot & 1] - (rrb_total); - - if (r > 0) { - pcibr_soft->bs_rrb_res[slot] = r; - pcibr_soft->bs_rrb_avail[slot & 1] -= r; - } - } - - pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft); - - return 0; - -} - -/* - * Dump the pcibr_soft_t RRB state variable - */ -void -pcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft) -{ - pciio_slot_t slot; - - if (pcibr_debug_mask & PCIBR_DEBUG_RRB) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "%s: rrbs available, even=%d, odd=%d\n", calling_func, - pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1])); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n")); - - for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, - "\t %d\t %d\t %d\t %d\t %d\t %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2], - 0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3], - pcibr_soft->bs_rrb_res[slot])); - } - } -} diff --git a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c deleted file mode 100644 index a4d7c5615..000000000 --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_slot.c +++ /dev/null @@ -1,1842 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern pcibr_info_t pcibr_info_get(vertex_hdl_t); -extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); -extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, pciio_function_t, pciio_vendor_id_t, pciio_device_id_t); -extern int pcibr_slot_initial_rrb_alloc(vertex_hdl_t,pciio_slot_t); -extern int pcibr_pcix_rbars_calc(pcibr_soft_t); - -extern char *pci_space[]; - -int pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, pciio_slot_t slot); -int pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot); -int pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, int drv_flags); -int pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, int drv_flags); -int pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, - int drv_flags, char *l1_msg, int *sub_errorp); -static int pcibr_probe_slot(pcibr_soft_t, cfg_p, unsigned int *); -static int pcibr_probe_work(pcibr_soft_t pcibr_soft, void *addr, int len, void *valp); -void pcibr_device_info_free(vertex_hdl_t, pciio_slot_t); -iopaddr_t pcibr_bus_addr_alloc(pcibr_soft_t, pciio_win_info_t, - pciio_space_t, int, int, int); -void pcibr_bus_addr_free(pciio_win_info_t); -cfg_p pcibr_find_capability(cfg_p, unsigned); -extern uint64_t do_pcibr_config_get(cfg_p, unsigned, unsigned); -void do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t); -int pcibr_slot_pwr(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot, int up, char *err_msg); - - -/* - * PCI-X Max Outstanding Split Transactions translation array and Max Memory - * Read Byte Count translation array, as defined in the PCI-X Specification. - * Section 7.2.3 & 7.2.4 of PCI-X Specification - rev 1.0 - */ -#define MAX_SPLIT_TABLE 8 -#define MAX_READCNT_TABLE 4 -int max_splittrans_to_numbuf[MAX_SPLIT_TABLE] = {1, 2, 3, 4, 8, 12, 16, 32}; -int max_readcount_to_bufsize[MAX_READCNT_TABLE] = {512, 1024, 2048, 4096 }; - -#ifdef CONFIG_HOTPLUG_PCI_SGI - -/* - * PCI slot manipulation errors from the system controller, and their - * associated descriptions - */ -#define SYSCTL_REQERR_BASE (-106000) -#define SYSCTL_PCI_ERROR_BASE (SYSCTL_REQERR_BASE - 100) -#define SYSCTL_PCIX_ERROR_BASE (SYSCTL_REQERR_BASE - 3000) - -struct sysctl_pci_error_s { - - int error; - char *msg; - -} sysctl_pci_errors[] = { - -#define SYSCTL_PCI_UNINITIALIZED (SYSCTL_PCI_ERROR_BASE - 0) - { SYSCTL_PCI_UNINITIALIZED, "module not initialized" }, - -#define SYSCTL_PCI_UNSUPPORTED_BUS (SYSCTL_PCI_ERROR_BASE - 1) - { SYSCTL_PCI_UNSUPPORTED_BUS, "unsupported bus" }, - -#define SYSCTL_PCI_UNSUPPORTED_SLOT (SYSCTL_PCI_ERROR_BASE - 2) - { SYSCTL_PCI_UNSUPPORTED_SLOT, "unsupported slot" }, - -#define SYSCTL_PCI_POWER_NOT_OKAY (SYSCTL_PCI_ERROR_BASE - 3) - { SYSCTL_PCI_POWER_NOT_OKAY, "slot power not okay" }, - -#define SYSCTL_PCI_CARD_NOT_PRESENT (SYSCTL_PCI_ERROR_BASE - 4) - { SYSCTL_PCI_CARD_NOT_PRESENT, "card not present" }, - -#define SYSCTL_PCI_POWER_LIMIT (SYSCTL_PCI_ERROR_BASE - 5) - { SYSCTL_PCI_POWER_LIMIT, "power limit reached - some cards not powered up" }, - -#define SYSCTL_PCI_33MHZ_ON_66MHZ (SYSCTL_PCI_ERROR_BASE - 6) - { SYSCTL_PCI_33MHZ_ON_66MHZ, "cannot add a 33 MHz card to an active 66 MHz bus" }, - -#define SYSCTL_PCI_INVALID_ORDER (SYSCTL_PCI_ERROR_BASE - 7) - { SYSCTL_PCI_INVALID_ORDER, "invalid reset order" }, - -#define SYSCTL_PCI_DOWN_33MHZ (SYSCTL_PCI_ERROR_BASE - 8) - { SYSCTL_PCI_DOWN_33MHZ, "cannot power down a 33 MHz card on an active bus" }, - -#define SYSCTL_PCI_RESET_33MHZ (SYSCTL_PCI_ERROR_BASE - 9) - { SYSCTL_PCI_RESET_33MHZ, "cannot reset a 33 MHz card on an active bus" }, - -#define SYSCTL_PCI_SLOT_NOT_UP (SYSCTL_PCI_ERROR_BASE - 10) - { SYSCTL_PCI_SLOT_NOT_UP, "cannot reset a slot that is not powered up" }, - -#define SYSCTL_PCIX_UNINITIALIZED (SYSCTL_PCIX_ERROR_BASE - 0) - { SYSCTL_PCIX_UNINITIALIZED, "module not initialized" }, - -#define SYSCTL_PCIX_UNSUPPORTED_BUS (SYSCTL_PCIX_ERROR_BASE - 1) - { SYSCTL_PCIX_UNSUPPORTED_BUS, "unsupported bus" }, - -#define SYSCTL_PCIX_UNSUPPORTED_SLOT (SYSCTL_PCIX_ERROR_BASE - 2) - { SYSCTL_PCIX_UNSUPPORTED_SLOT, "unsupported slot" }, - -#define SYSCTL_PCIX_POWER_NOT_OKAY (SYSCTL_PCIX_ERROR_BASE - 3) - { SYSCTL_PCIX_POWER_NOT_OKAY, "slot power not okay" }, - -#define SYSCTL_PCIX_CARD_NOT_PRESENT (SYSCTL_PCIX_ERROR_BASE - 4) - { SYSCTL_PCIX_CARD_NOT_PRESENT, "card not present" }, - -#define SYSCTL_PCIX_POWER_LIMIT (SYSCTL_PCIX_ERROR_BASE - 5) - { SYSCTL_PCIX_POWER_LIMIT, "power limit reached - some cards not powered up" }, - -#define SYSCTL_PCIX_33MHZ_ON_66MHZ (SYSCTL_PCIX_ERROR_BASE - 6) - { SYSCTL_PCIX_33MHZ_ON_66MHZ, "cannot add a 33 MHz card to an active 66 MHz bus" }, - -#define SYSCTL_PCIX_PCI_ON_PCIX (SYSCTL_PCIX_ERROR_BASE - 7) - { SYSCTL_PCIX_PCI_ON_PCIX, "cannot add a PCI card to an active PCIX bus" }, - -#define SYSCTL_PCIX_ANYTHING_ON_133MHZ (SYSCTL_PCIX_ERROR_BASE - 8) - { SYSCTL_PCIX_ANYTHING_ON_133MHZ, "cannot add any card to an active 133MHz PCIX bus" }, - -#define SYSCTL_PCIX_X66MHZ_ON_X100MHZ (SYSCTL_PCIX_ERROR_BASE - 9) - { SYSCTL_PCIX_X66MHZ_ON_X100MHZ, "cannot add a PCIX 66MHz card to an active 100MHz PCIX bus" }, - -#define SYSCTL_PCIX_INVALID_ORDER (SYSCTL_PCIX_ERROR_BASE - 10) - { SYSCTL_PCIX_INVALID_ORDER, "invalid reset order" }, - -#define SYSCTL_PCIX_DOWN_33MHZ (SYSCTL_PCIX_ERROR_BASE - 11) - { SYSCTL_PCIX_DOWN_33MHZ, "cannot power down a 33 MHz card on an active bus" }, - -#define SYSCTL_PCIX_RESET_33MHZ (SYSCTL_PCIX_ERROR_BASE - 12) - { SYSCTL_PCIX_RESET_33MHZ, "cannot reset a 33 MHz card on an active bus" }, - -#define SYSCTL_PCIX_SLOT_NOT_UP (SYSCTL_PCIX_ERROR_BASE - 13) - { SYSCTL_PCIX_SLOT_NOT_UP, "cannot reset a slot that is not powered up" }, - -#define SYSCTL_PCIX_INVALID_BUS_SETTING (SYSCTL_PCIX_ERROR_BASE - 14) - { SYSCTL_PCIX_INVALID_BUS_SETTING, "invalid bus type/speed selection (PCIX<66MHz, PCI>66MHz)" }, - -#define SYSCTL_PCIX_INVALID_DEPENDENT_SLOT (SYSCTL_PCIX_ERROR_BASE - 15) - { SYSCTL_PCIX_INVALID_DEPENDENT_SLOT, "invalid dependent slot in PCI slot configuration" }, - -#define SYSCTL_PCIX_SHARED_IDSELECT (SYSCTL_PCIX_ERROR_BASE - 16) - { SYSCTL_PCIX_SHARED_IDSELECT, "cannot enable two slots sharing the same IDSELECT" }, - -#define SYSCTL_PCIX_SLOT_DISABLED (SYSCTL_PCIX_ERROR_BASE - 17) - { SYSCTL_PCIX_SLOT_DISABLED, "slot is disabled" }, - -}; /* end sysctl_pci_errors[] */ - -/* - * look up an error message for PCI operations that fail - */ -static void -sysctl_pci_error_lookup(int error, char *err_msg) -{ - int i; - struct sysctl_pci_error_s *e = sysctl_pci_errors; - - for (i = 0; - i < (sizeof(sysctl_pci_errors) / sizeof(*e)); - i++, e++ ) - { - if (e->error == error) - { - strcpy(err_msg, e->msg); - return; - } - } - - sprintf(err_msg, "unrecognized PCI error type"); -} - -/* - * pcibr_slot_attach - * This is a place holder routine to keep track of all the - * slot-specific initialization that needs to be done. - * This is usually called when we want to initialize a new - * PCI card on the bus. - */ -int -pcibr_slot_attach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags, - char *l1_msg, - int *sub_errorp) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - int error; - - if (!(pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_POWER_ON)) { - uint64_t speed; - uint64_t mode; - - /* Power-up the slot */ - error = pcibr_slot_pwr(pcibr_vhdl, slot, PCI_REQ_SLOT_POWER_ON, l1_msg); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_L1_ERR); - } else { - pcibr_soft->bs_slot[slot].slot_status &= ~PCI_SLOT_POWER_MASK; - pcibr_soft->bs_slot[slot].slot_status |= PCI_SLOT_POWER_ON; - } - - /* The speed/mode of the bus may have changed due to the hotplug */ - speed = pcireg_speed_get(pcibr_soft); - mode = pcireg_mode_get(pcibr_soft); - pcibr_soft->bs_bridge_mode = ((speed << 1) | mode); - - /* - * Allow cards like the Alteon Gigabit Ethernet Adapter to complete - * on-card initialization following the slot reset - */ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (HZ); - - /* Find out what is out there */ - error = pcibr_slot_info_init(pcibr_vhdl, slot); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_INFO_INIT_ERR); - } - - /* Set up the address space for this slot in the PCI land */ - - error = pcibr_slot_addr_space_init(pcibr_vhdl, slot); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_ADDR_INIT_ERR); - } - - /* Allocate the PCI-X Read Buffer Attribute Registers (RBARs)*/ - if (IS_PCIX(pcibr_soft)) { - int tmp_slot; - - /* Recalculate the RBARs for all the devices on the bus. Only - * return an error if we error for the given 'slot' - */ - pcibr_soft->bs_pcix_rbar_inuse = 0; - pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; - pcibr_soft->bs_pcix_rbar_percent_allowed = - pcibr_pcix_rbars_calc(pcibr_soft); - for (tmp_slot = pcibr_soft->bs_min_slot; - tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot) { - if (tmp_slot == slot) - continue; /* skip this 'slot', we do it below */ - (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot); - } - - error = pcibr_slot_pcix_rbar_init(pcibr_soft, slot); - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_RBAR_ALLOC_ERR); - } - } - - /* Setup the device register */ - error = pcibr_slot_device_init(pcibr_vhdl, slot); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_DEV_INIT_ERR); - } - - /* Setup host/guest relations */ - error = pcibr_slot_guest_info_init(pcibr_vhdl, slot); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_GUEST_INIT_ERR); - } - - /* Initial RRB management */ - error = pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - return(PCI_SLOT_RRB_ALLOC_ERR); - } - - } - - /* Call the device attach */ - error = pcibr_slot_call_device_attach(pcibr_vhdl, slot, drv_flags); - - if (error) { - if (sub_errorp) - *sub_errorp = error; - if (error == EUNATCH) - return(PCI_NO_DRIVER); - else - return(PCI_SLOT_DRV_ATTACH_ERR); - } - - return(0); -} - -/* - * pcibr_slot_enable - * Enable the PCI slot for a hot-plug insert. - */ -int -pcibr_slot_enable(vertex_hdl_t pcibr_vhdl, struct pcibr_slot_enable_req_s *req_p) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = req_p->req_device; - int error = 0; - - /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) { - return(PCI_NOT_A_BRIDGE); - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl, - "pcibr_slot_enable: pcibr_soft=0x%lx, slot=%d, req_p=0x%lx\n", - pcibr_soft, slot, req_p)); - - /* Check for the valid slot */ - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(PCI_NOT_A_SLOT); - - if (pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_ENABLE_CMPLT) { - error = PCI_SLOT_ALREADY_UP; - goto enable_unlock; - } - - error = pcibr_slot_attach(pcibr_vhdl, slot, 0, - req_p->req_resp.resp_l1_msg, - &req_p->req_resp.resp_sub_errno); - - req_p->req_resp.resp_l1_msg[PCI_L1_QSIZE] = '\0'; - - enable_unlock: - - return(error); -} - -/* - * pcibr_slot_disable - * Disable the PCI slot for a hot-plug removal. - */ -int -pcibr_slot_disable(vertex_hdl_t pcibr_vhdl, struct pcibr_slot_disable_req_s *req_p) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pciio_slot_t slot = req_p->req_device; - int error = 0; - pciio_slot_t tmp_slot; - - /* Make sure that we are dealing with a bridge device vertex */ - if (!pcibr_soft) { - return(PCI_NOT_A_BRIDGE); - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HOTPLUG, pcibr_vhdl, - "pcibr_slot_disable: pcibr_soft=0x%lx, slot=%d, req_p=0x%lx\n", - pcibr_soft, slot, req_p)); - - /* Check for valid slot */ - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return(PCI_NOT_A_SLOT); - - if ((pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_DISABLE_CMPLT) || - ((pcibr_soft->bs_slot[slot].slot_status & PCI_SLOT_STATUS_MASK) == 0)) { - error = PCI_SLOT_ALREADY_DOWN; - /* - * RJR - Should we invoke an L1 slot power-down command just in case - * a previous shut-down failed to power-down the slot? - */ - goto disable_unlock; - } - - /* Do not allow the last 33 MHz card to be removed */ - if (IS_33MHZ(pcibr_soft)) { - for (tmp_slot = pcibr_soft->bs_first_slot; - tmp_slot <= pcibr_soft->bs_last_slot; tmp_slot++) - if (tmp_slot != slot) - if (pcibr_soft->bs_slot[tmp_slot].slot_status & PCI_SLOT_POWER_ON) { - error++; - break; - } - if (!error) { - error = PCI_EMPTY_33MHZ; - goto disable_unlock; - } - } - - if (req_p->req_action == PCI_REQ_SLOT_ELIGIBLE) - return(0); - - error = pcibr_slot_detach(pcibr_vhdl, slot, 1, - req_p->req_resp.resp_l1_msg, - &req_p->req_resp.resp_sub_errno); - - req_p->req_resp.resp_l1_msg[PCI_L1_QSIZE] = '\0'; - - disable_unlock: - - return(error); -} - -/* - * pcibr_slot_pwr - * Power-up or power-down a PCI slot. This routines makes calls to - * the L1 system controller driver which requires "external" slot#. - */ -int -pcibr_slot_pwr(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int up, - char *err_msg) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - nasid_t nasid; - u64 connection_type; - int rv; - - nasid = NASID_GET(pcibr_soft->bs_base); - connection_type = SAL_SYSCTL_IO_XTALK; - - rv = (int) ia64_sn_sysctl_iobrick_pci_op - (nasid, - connection_type, - (u64) pcibr_widget_to_bus(pcibr_vhdl), - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - (up ? SAL_SYSCTL_PCI_POWER_UP : SAL_SYSCTL_PCI_POWER_DOWN)); - - if (!rv) { - /* everything's okay; no error message */ - *err_msg = '\0'; - } - else { - /* there was a problem; look up an appropriate error message */ - sysctl_pci_error_lookup(rv, err_msg); - } - return rv; -} - -#endif /* CONFIG_HOTPLUG_PCI_SGI */ - -/* - * pcibr_slot_info_init - * Probe for this slot and see if it is populated. - * If it is populated initialize the generic PCI infrastructural - * information associated with this particular PCI device. - */ -int -pcibr_slot_info_init(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - cfg_p cfgw; - unsigned idword; - unsigned pfail; - unsigned idwords[8]; - pciio_vendor_id_t vendor; - pciio_device_id_t device; - unsigned htype; - unsigned lt_time; - int nbars; - cfg_p wptr; - cfg_p pcix_cap; - int win; - pciio_space_t space; - int nfunc; - pciio_function_t rfunc; - int func; - vertex_hdl_t conn_vhdl; - pcibr_soft_slot_t slotp; - uint64_t device_reg; - - /* Get the basic software information required to proceed */ - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - /* If we have a host slot (eg:- IOC3 has 2 PCI slots and the initialization - * is done by the host slot then we are done. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return 0; - } - - /* Try to read the device-id/vendor-id from the config space */ - cfgw = pcibr_slot_config_addr(pcibr_soft, slot, 0); - - if (pcibr_probe_slot(pcibr_soft, cfgw, &idword)) - return -ENODEV; - - slotp = &pcibr_soft->bs_slot[slot]; -#ifdef CONFIG_HOTPLUG_PCI_SGI - slotp->slot_status |= SLOT_POWER_UP; -#endif - - vendor = 0xFFFF & idword; - device = 0xFFFF & (idword >> 16); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_PROBE, pcibr_vhdl, - "pcibr_slot_info_init: slot=%d, vendor=0x%x, device=0x%x\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vendor, device)); - - /* If the vendor id is not valid then the slot is not populated - * and we are done. - */ - if (vendor == 0xFFFF) - return -ENODEV; - - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - nfunc = 1; - rfunc = PCIIO_FUNC_NONE; - pfail = 0; - - /* NOTE: if a card claims to be multifunction - * but only responds to config space 0, treat - * it as a unifunction card. - */ - - if (htype & 0x80) { /* MULTIFUNCTION */ - for (func = 1; func < 8; ++func) { - cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); - if (pcibr_probe_slot(pcibr_soft, cfgw, &idwords[func])) { - pfail |= 1 << func; - continue; - } - vendor = 0xFFFF & idwords[func]; - if (vendor == 0xFFFF) { - pfail |= 1 << func; - continue; - } - nfunc = func + 1; - rfunc = 0; - } - cfgw = pcibr_slot_config_addr(pcibr_soft, slot, 0); - } - pcibr_infoh = kmalloc(nfunc*sizeof (*(pcibr_infoh)), GFP_KERNEL); - if ( !pcibr_infoh ) { - return -ENOMEM; - } - memset(pcibr_infoh, 0, nfunc*sizeof (*(pcibr_infoh))); - - pcibr_soft->bs_slot[slot].bss_ninfo = nfunc; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - for (func = 0; func < nfunc; ++func) { - unsigned cmd_reg; - - if (func) { - if (pfail & (1 << func)) - continue; - - idword = idwords[func]; - cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); - - device = 0xFFFF & (idword >> 16); - htype = do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1); - rfunc = func; - } - htype &= 0x7f; - if (htype != 0x00) { - printk(KERN_WARNING - "%s pcibr: pci slot %d func %d has strange header type 0x%x\n", - pcibr_soft->bs_name, slot, func, htype); - nbars = 2; - } else { - nbars = PCI_CFG_BASE_ADDRS; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, - "pcibr_slot_info_init: slot=%d, func=%d, cfgw=0x%lx\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), func, cfgw)); - - /* - * If the latency timer has already been set, by prom or by the - * card itself, use that value. Otherwise look at the device's - * 'min_gnt' and attempt to calculate a latency time. - * - * NOTE: For now if the device is on the 'real time' arbitration - * ring we don't set the latency timer. - * - * WAR: SGI's IOC3 and RAD devices target abort if you write a - * single byte into their config space. So don't set the Latency - * Timer for these devices - */ - - lt_time = do_pcibr_config_get(cfgw, PCI_CFG_LATENCY_TIMER, 1); - device_reg = pcireg_device_get(pcibr_soft, slot); - if ((lt_time == 0) && !(device_reg & BRIDGE_DEV_RT)) { - unsigned min_gnt; - unsigned min_gnt_mult; - - /* 'min_gnt' indicates how long of a burst period a device - * needs in increments of 250ns. But latency timer is in - * PCI clock cycles, so a conversion is needed. - */ - min_gnt = do_pcibr_config_get(cfgw, PCI_MIN_GNT, 1); - - if (IS_133MHZ(pcibr_soft)) - min_gnt_mult = 32; /* 250ns @ 133MHz in clocks */ - else if (IS_100MHZ(pcibr_soft)) - min_gnt_mult = 24; /* 250ns @ 100MHz in clocks */ - else if (IS_66MHZ(pcibr_soft)) - min_gnt_mult = 16; /* 250ns @ 66MHz, in clocks */ - else - min_gnt_mult = 8; /* 250ns @ 33MHz, in clocks */ - - if ((min_gnt != 0) && ((min_gnt * min_gnt_mult) < 256)) - lt_time = (min_gnt * min_gnt_mult); - else - lt_time = 4 * min_gnt_mult; /* 1 micro second */ - - do_pcibr_config_set(cfgw, PCI_CFG_LATENCY_TIMER, 1, lt_time); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, - "pcibr_slot_info_init: set Latency Timer for slot=%d, " - "func=%d, to 0x%x\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, lt_time)); - } - - - /* In our architecture the setting of the cacheline size isn't - * beneficial for cards in PCI mode, but in PCI-X mode devices - * can optionally use the cacheline size value for internal - * device optimizations (See 7.1.5 of the PCI-X v1.0 spec). - * NOTE: cachline size is in doubleword increments - */ - if (IS_PCIX(pcibr_soft)) { - if (!do_pcibr_config_get(cfgw, PCI_CFG_CACHE_LINE, 1)) { - do_pcibr_config_set(cfgw, PCI_CFG_CACHE_LINE, 1, 0x20); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, - "pcibr_slot_info_init: set CacheLine for slot=%d, " - "func=%d, to 0x20\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); - } - } - - /* Get the PCI-X capability if running in PCI-X mode. If the func - * doesnt have a pcix capability, allocate a PCIIO_VENDOR_ID_NONE - * pcibr_info struct so the device driver for that function is not - * called. - */ - if (IS_PCIX(pcibr_soft)) { - if (!(pcix_cap = pcibr_find_capability(cfgw, PCI_CAP_PCIX))) { - printk(KERN_WARNING - "%s: Bus running in PCI-X mode, But card in slot %d, " - "func %d not PCI-X capable\n", - pcibr_soft->bs_name, slot, func); - pcibr_device_info_new(pcibr_soft, slot, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - continue; - } - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_CONFIG, pcibr_vhdl, - "pcibr_slot_info_init: PCI-X capability at 0x%lx for " - "slot=%d, func=%d\n", - pcix_cap, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func)); - } else { - pcix_cap = NULL; - } - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, rfunc, vendor, device); - - /* Keep a running total of the number of PIC-X functions on the bus - * and the number of max outstanding split trasnactions that they - * have requested. NOTE: "pcix_cap != NULL" implies IS_PCIX() - */ - pcibr_info->f_pcix_cap = (cap_pcix_type0_t *)pcix_cap; - if (pcibr_info->f_pcix_cap) { - int max_out; /* max outstanding splittrans from status reg */ - - pcibr_soft->bs_pcix_num_funcs++; - max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split; - pcibr_soft->bs_pcix_split_tot += max_splittrans_to_numbuf[max_out]; - } - - conn_vhdl = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); - if (func == 0) - slotp->slot_conn = conn_vhdl; - - cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); - - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - for (win = 0; win < nbars; ++win) { - iopaddr_t base, mask, code; - size_t size; - - /* - * GET THE BASE & SIZE OF THIS WINDOW: - * - * The low two or four bits of the BASE register - * determines which address space we are in; the - * rest is a base address. BASE registers - * determine windows that are power-of-two sized - * and naturally aligned, so we can get the size - * of a window by writing all-ones to the - * register, reading it back, and seeing which - * bits are used for decode; the least - * significant nonzero bit is also the size of - * the window. - * - * WARNING: someone may already have allocated - * some PCI space to this window, and in fact - * PIO may be in process at this very moment - * from another processor (or even from this - * one, if we get interrupted)! So, if the BASE - * already has a nonzero address, be generous - * and use the LSBit of that address as the - * size; this could overstate the window size. - * Usually, when one card is set up, all are set - * up; so, since we don't bitch about - * overlapping windows, we are ok. - * - * UNFORTUNATELY, some cards do not clear their - * BASE registers on reset. I have two heuristics - * that can detect such cards: first, if the - * decode enable is turned off for the space - * that the window uses, we can disregard the - * initial value. second, if the address is - * outside the range that we use, we can disregard - * it as well. - * - * This is looking very PCI generic. Except for - * knowing how many slots and where their config - * spaces are, this window loop and the next one - * could probably be shared with other PCI host - * adapters. It would be interesting to see if - * this could be pushed up into pciio, when we - * start supporting more PCI providers. - */ - base = do_pcibr_config_get(wptr, (win * 4), 4); - - if (base & PCI_BA_IO_SPACE) { - /* BASE is in I/O space. */ - space = PCIIO_SPACE_IO; - mask = -4; - code = base & 3; - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_IO_SPACE)) { - base = 0; /* decode not enabled */ - } - } else { - /* BASE is in MEM space. */ - space = PCIIO_SPACE_MEM; - mask = -16; - code = base & PCI_BA_MEM_LOCATION; /* extract BAR type */ - base = base & mask; - if (base == 0) { - ; /* not assigned */ - } else if (!(cmd_reg & PCI_CMD_MEM_SPACE)) { - base = 0; /* decode not enabled */ - } else if (base & 0xC0000000) { - base = 0; /* outside permissable range */ - } else if ((code == PCI_BA_MEM_64BIT) && - (do_pcibr_config_get(wptr, ((win + 1)*4), 4) != 0)) { - base = 0; /* outside permissable range */ - } - } - - if (base != 0) { /* estimate size */ - pciio_space_t tmp_space = space; - iopaddr_t tmp_base; - - size = base & -base; - - /* - * Reserve this space in the relavent address map. Don't - * care about the return code from pcibr_bus_addr_alloc(). - */ - - if (space == PCIIO_SPACE_MEM && code != PCI_BA_MEM_1MEG) { - tmp_space = PCIIO_SPACE_MEM32; - } - - tmp_base = pcibr_bus_addr_alloc(pcibr_soft, - &pcibr_info->f_window[win], - tmp_space, - base, size, 0); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_info_init: slot=%d, func=%d win %d " - "reserving space %s [0x%lx..0x%lx], tmp_base 0x%lx\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, - pci_space[tmp_space], (uint64_t)base, - (uint64_t)(base + size - 1), (uint64_t)tmp_base)); - } else { /* calculate size */ - do_pcibr_config_set(wptr, (win * 4), 4, ~0); /* write 1's */ - size = do_pcibr_config_get(wptr, (win * 4), 4); /* read back */ - size &= mask; /* keep addr */ - size &= -size; /* keep lsbit */ - if (size == 0) - continue; - } - - pcibr_info->f_window[win].w_space = space; - pcibr_info->f_window[win].w_base = base; - pcibr_info->f_window[win].w_size = size; - - if (code == PCI_BA_MEM_64BIT) { - win++; /* skip upper half */ - do_pcibr_config_set(wptr, (win * 4), 4, 0); /* must be zero */ - } - } /* next win */ - } /* next func */ - - return 0; -} - -/* - * pcibr_find_capability - * Walk the list of capabilities (if it exists) looking for - * the requested capability. Return a cfg_p pointer to the - * capability if found, else return NULL - */ -cfg_p -pcibr_find_capability(cfg_p cfgw, - unsigned capability) -{ - unsigned cap_nxt; - unsigned cap_id; - int defend_against_circular_linkedlist = 0; - - /* Check to see if there is a capabilities pointer in the cfg header */ - if (!(do_pcibr_config_get(cfgw, PCI_CFG_STATUS, 2) & PCI_STAT_CAP_LIST)) { - return NULL; - } - - /* - * Read up the capabilities head pointer from the configuration header. - * Capabilities are stored as a linked list in the lower 48 dwords of - * config space and are dword aligned. (Note: spec states the least two - * significant bits of the next pointer must be ignored, so we mask - * with 0xfc). - */ - cap_nxt = (do_pcibr_config_get(cfgw, PCI_CAPABILITIES_PTR, 1) & 0xfc); - - while (cap_nxt && (defend_against_circular_linkedlist <= 48)) { - cap_id = do_pcibr_config_get(cfgw, cap_nxt, 1); - if (cap_id == capability) { - return (cfg_p)((char *)cfgw + cap_nxt); - } - cap_nxt = (do_pcibr_config_get(cfgw, cap_nxt+1, 1) & 0xfc); - defend_against_circular_linkedlist++; - } - - return NULL; -} - -/* - * pcibr_slot_info_free - * Remove all the PCI infrastructural information associated - * with a particular PCI device. - */ -int -pcibr_slot_info_free(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - int nfunc; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - - pcibr_device_info_free(pcibr_vhdl, slot); - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - kfree(pcibr_infoh); - pcibr_soft->bs_slot[slot].bss_ninfo = 0; - - return 0; -} - -/* - * pcibr_slot_pcix_rbar_init - * Allocate RBARs to the PCI-X functions on a given device - */ -int -pcibr_slot_pcix_rbar_init(pcibr_soft_t pcibr_soft, - pciio_slot_t slot) -{ - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int nfunc; - int func; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - if ((nfunc = pcibr_soft->bs_slot[slot].bss_ninfo) < 1) - return -EINVAL; - - if (!(pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos)) - return -EINVAL; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, - "pcibr_slot_pcix_rbar_init for slot %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot))); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, - "\tslot/func\trequested\tgiven\tinuse\tavail\n")); - - for (func = 0; func < nfunc; ++func) { - cap_pcix_type0_t *pcix_cap_p; - cap_pcix_stat_reg_t *pcix_statreg_p; - cap_pcix_cmd_reg_t *pcix_cmdreg_p; - int num_rbar; - - if (!(pcibr_info = pcibr_infoh[func])) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - if (!(pcix_cap_p = pcibr_info->f_pcix_cap)) - continue; - - pcix_statreg_p = &pcix_cap_p->pcix_type0_status; - pcix_cmdreg_p = &pcix_cap_p->pcix_type0_command; - - /* If there are enough RBARs to satify the number of "max outstanding - * transactions" each function requested (bs_pcix_rbar_percent_allowed - * is 100%), then give each function what it requested, otherwise give - * the functions a "percentage of what they requested". - */ - if (pcibr_soft->bs_pcix_rbar_percent_allowed >= 100) { - pcix_cmdreg_p->max_split = pcix_statreg_p->max_out_split; - num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; - pcibr_soft->bs_pcix_rbar_inuse += num_rbar; - pcibr_soft->bs_pcix_rbar_avail -= num_rbar; - pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; - } else { - int index; /* index into max_splittrans_to_numbuf table */ - int max_out; /* max outstanding transactions given to func */ - - /* Calculate the percentage of RBARs this function can have. - * NOTE: Every function gets at least 1 RBAR (thus the "+1"). - * bs_pcix_rbar_percent_allowed is the percentage of what was - * requested less this 1 RBAR that all functions automatically - * gets - */ - max_out = ((max_splittrans_to_numbuf[pcix_statreg_p->max_out_split] - * pcibr_soft->bs_pcix_rbar_percent_allowed) / 100) + 1; - - /* round down the newly caclulated max_out to a valid number in - * max_splittrans_to_numbuf[] - */ - for (index = 0; index < MAX_SPLIT_TABLE-1; index++) - if (max_splittrans_to_numbuf[index + 1] > max_out) - break; - - pcix_cmdreg_p->max_split = index; - num_rbar = max_splittrans_to_numbuf[pcix_cmdreg_p->max_split]; - pcibr_soft->bs_pcix_rbar_inuse += num_rbar; - pcibr_soft->bs_pcix_rbar_avail -= num_rbar; - pcix_cmdreg_p->max_mem_read_cnt = pcix_statreg_p->max_mem_read_cnt; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RBAR, pcibr_soft->bs_vhdl, - "\t %d/%d \t %d \t %d \t %d \t %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, - max_splittrans_to_numbuf[pcix_statreg_p->max_out_split], - max_splittrans_to_numbuf[pcix_cmdreg_p->max_split], - pcibr_soft->bs_pcix_rbar_inuse, - pcibr_soft->bs_pcix_rbar_avail)); - } - return 0; -} - -int as_debug = 0; -/* - * pcibr_slot_addr_space_init - * Reserve chunks of PCI address space as required by - * the base registers in the card. - */ -int -pcibr_slot_addr_space_init(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - iopaddr_t mask; - int nbars; - int nfunc; - int func; - int win; - int rc = 0; - int align = 0; - int align_slot; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - /* allocate address space, - * for windows that have not been - * previously assigned. - */ - if (pcibr_soft->bs_slot[slot].has_host) { - return 0; - } - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - if (nfunc < 1) - return -EINVAL; - - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - if (!pcibr_infoh) - return -EINVAL; - - /* - * Try to make the DevIO windows not - * overlap by pushing the "io" and "hi" - * allocation areas up to the next one - * or two megabyte bound. This also - * keeps them from being zero. - * - * DO NOT do this with "pci_lo" since - * the entire "lo" area is only a - * megabyte, total ... - */ - align_slot = (slot < 2) ? 0x200000 : 0x100000; - - for (func = 0; func < nfunc; ++func) { - cfg_p cfgw; - cfg_p wptr; - pciio_space_t space; - iopaddr_t base; - size_t size; - unsigned pci_cfg_cmd_reg; - unsigned pci_cfg_cmd_reg_add = 0; - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); - wptr = cfgw + PCI_CFG_BASE_ADDR_0 / 4; - - if ((do_pcibr_config_get(cfgw, PCI_CFG_HEADER_TYPE, 1) & 0x7f) != 0) - nbars = 2; - else - nbars = PCI_CFG_BASE_ADDRS; - - for (win = 0; win < nbars; ++win) { - space = pcibr_info->f_window[win].w_space; - base = pcibr_info->f_window[win].w_base; - size = pcibr_info->f_window[win].w_size; - - if (size < 1) - continue; - - if (base >= size) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_addr_space_init: slot=%d, " - "func=%d win %d is in space %s [0x%lx..0x%lx], " - "allocated by prom\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, - pci_space[space], (uint64_t)base, - (uint64_t)(base + size - 1))); - - continue; /* already allocated */ - } - - align = (win) ? size : align_slot; - - if (align < PAGE_SIZE) - align = PAGE_SIZE; /* ie. 0x00004000 */ - - switch (space) { - case PCIIO_SPACE_IO: - base = pcibr_bus_addr_alloc(pcibr_soft, - &pcibr_info->f_window[win], - PCIIO_SPACE_IO, - 0, size, align); - if (!base) - rc = ENOSPC; - break; - - case PCIIO_SPACE_MEM: - if ((do_pcibr_config_get(wptr, (win * 4), 4) & - PCI_BA_MEM_LOCATION) == PCI_BA_MEM_1MEG) { - - /* allocate from 20-bit PCI space */ - base = pcibr_bus_addr_alloc(pcibr_soft, - &pcibr_info->f_window[win], - PCIIO_SPACE_MEM, - 0, size, align); - if (!base) - rc = ENOSPC; - } else { - /* allocate from 32-bit or 64-bit PCI space */ - base = pcibr_bus_addr_alloc(pcibr_soft, - &pcibr_info->f_window[win], - PCIIO_SPACE_MEM32, - 0, size, align); - if (!base) - rc = ENOSPC; - } - break; - - default: - base = 0; - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_addr_space_init: slot=%d, window %d " - "had bad space code %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft,slot), win, space)); - } - pcibr_info->f_window[win].w_base = base; - do_pcibr_config_set(wptr, (win * 4), 4, base); - - if (base >= size) { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_addr_space_init: slot=%d, func=%d. win %d " - "is in space %s [0x%lx..0x%lx], allocated by pcibr\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, - pci_space[space], (uint64_t)base, - (uint64_t)(base + size - 1))); - } else { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_addr_space_init: slot=%d, func=%d, win %d, " - "unable to alloc 0x%lx in space %s\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, win, - (uint64_t)size, pci_space[space])); - } - } /* next base */ - - /* - * Allocate space for the EXPANSION ROM - */ - base = size = 0; - { - wptr = cfgw + PCI_EXPANSION_ROM / 4; - do_pcibr_config_set(wptr, 0, 4, 0xFFFFF000); - mask = do_pcibr_config_get(wptr, 0, 4); - if (mask & 0xFFFFF000) { - size = mask & -mask; - base = pcibr_bus_addr_alloc(pcibr_soft, - &pcibr_info->f_rwindow, - PCIIO_SPACE_MEM32, - 0, size, align); - if (!base) - rc = ENOSPC; - else { - do_pcibr_config_set(wptr, 0, 4, base); - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_BAR, pcibr_vhdl, - "pcibr_slot_addr_space_init: slot=%d, func=%d, " - "ROM in [0x%X..0x%X], allocated by pcibr\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), - func, base, base + size - 1)); - } - } - } - pcibr_info->f_rbase = base; - pcibr_info->f_rsize = size; - - /* - * if necessary, update the board's - * command register to enable decoding - * in the windows we added. - * - * There are some bits we always want to - * be sure are set. - */ - pci_cfg_cmd_reg_add |= PCI_CMD_IO_SPACE; - - /* - * The Adaptec 1160 FC Controller WAR #767995: - * The part incorrectly ignores the upper 32 bits of a 64 bit - * address when decoding references to its registers so to - * keep it from responding to a bus cycle that it shouldn't - * we only use I/O space to get at it's registers. Don't - * enable memory space accesses on that PCI device. - */ - #define FCADP_VENDID 0x9004 /* Adaptec Vendor ID from fcadp.h */ - #define FCADP_DEVID 0x1160 /* Adaptec 1160 Device ID from fcadp.h */ - - if ((pcibr_info->f_vendor != FCADP_VENDID) || - (pcibr_info->f_device != FCADP_DEVID)) - pci_cfg_cmd_reg_add |= PCI_CMD_MEM_SPACE; - - pci_cfg_cmd_reg_add |= PCI_CMD_BUS_MASTER; - - pci_cfg_cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); - pci_cfg_cmd_reg &= 0xFFFF; - if (pci_cfg_cmd_reg_add & ~pci_cfg_cmd_reg) - do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, - pci_cfg_cmd_reg | pci_cfg_cmd_reg_add); - } /* next func */ - return rc; -} - -/* - * pcibr_slot_device_init - * Setup the device register in the bridge for this PCI slot. - */ - -int -pcibr_slot_device_init(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - uint64_t devreg; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - /* - * Adjustments to Device(x) and init of bss_device shadow - */ - devreg = pcireg_device_get(pcibr_soft, slot); - devreg &= ~BRIDGE_DEV_PAGE_CHK_DIS; - - /* - * Enable virtual channels by default (exception: see PIC WAR below) - */ - devreg |= BRIDGE_DEV_VIRTUAL_EN; - - /* - * PIC WAR. PV# 855271: Disable virtual channels in the PIC since - * it can cause problems with 32-bit devices. We'll set the bit in - * pcibr_try_set_device() iff we're 64-bit and requesting virtual - * channels. - */ - if (PCIBR_WAR_ENABLED(PV855271, pcibr_soft)) { - devreg &= ~BRIDGE_DEV_VIRTUAL_EN; - } - devreg |= BRIDGE_DEV_COH; - - pcibr_soft->bs_slot[slot].bss_device = devreg; - pcireg_device_set(pcibr_soft, slot, devreg); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEVREG, pcibr_vhdl, - "pcibr_slot_device_init: Device(%d): 0x%x\n", - slot, devreg)); - return 0; -} - -/* - * pcibr_slot_guest_info_init - * Setup the host/guest relations for a PCI slot. - */ -int -pcibr_slot_guest_info_init(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - pcibr_soft_slot_t slotp; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - slotp = &pcibr_soft->bs_slot[slot]; - - /* create info and verticies for guest slots; - * for compatibilitiy macros, create info - * for even unpopulated slots (but do not - * build verticies for them). - */ - if (pcibr_soft->bs_slot[slot].bss_ninfo < 1) { - pcibr_infoh = kmalloc(sizeof (*(pcibr_infoh)), GFP_KERNEL); - if ( !pcibr_infoh ) { - return -ENOMEM; - } - memset(pcibr_infoh, 0, sizeof (*(pcibr_infoh))); - - pcibr_soft->bs_slot[slot].bss_ninfo = 1; - pcibr_soft->bs_slot[slot].bss_infos = pcibr_infoh; - - pcibr_info = pcibr_device_info_new - (pcibr_soft, slot, PCIIO_FUNC_NONE, - PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - - if (pcibr_soft->bs_slot[slot].has_host) { - slotp->slot_conn = pciio_device_info_register - (pcibr_vhdl, &pcibr_info->f_c); - } - } - - /* generate host/guest relations - */ - if (pcibr_soft->bs_slot[slot].has_host) { - int host = pcibr_soft->bs_slot[slot].host_slot; - pcibr_soft_slot_t host_slotp = &pcibr_soft->bs_slot[host]; - - hwgraph_edge_add(slotp->slot_conn, - host_slotp->slot_conn, - EDGE_LBL_HOST); - - /* XXX- only gives us one guest edge per - * host. If/when we have a host with more than - * one guest, we will need to figure out how - * the host finds all its guests, and sorts - * out which one is which. - */ - hwgraph_edge_add(host_slotp->slot_conn, - slotp->slot_conn, - EDGE_LBL_GUEST); - } - - return 0; -} - - -/* - * pcibr_slot_call_device_attach - * This calls the associated driver attach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_attach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int func; - vertex_hdl_t xconn_vhdl, conn_vhdl; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - if (pcibr_soft->bs_slot[slot].has_host) { - return -EPERM; - } - - xconn_vhdl = pcibr_soft->bs_conn; - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - conn_vhdl = pcibr_info->f_vertex; - - error_func = pciio_device_attach(conn_vhdl, drv_flags); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_ATTACH, pcibr_vhdl, - "pcibr_slot_call_device_attach: slot=%d, func=%d " - "drv_flags=0x%x, pciio_device_attach returned %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, - drv_flags, error_func)); - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - -#ifdef CONFIG_HOTPLUG_PCI_SGI - if (error) { - if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_INCMPLT; - } - } else { - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - pcibr_soft->bs_slot[slot].slot_status |= SLOT_STARTUP_CMPLT; - } -#endif /* CONFIG_HOTPLUG_PCI_SGI */ - return error; -} - -/* - * pcibr_slot_call_device_detach - * This calls the associated driver detach routine for the PCI - * card in this slot. - */ -int -pcibr_slot_call_device_detach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags) -{ - pcibr_soft_t pcibr_soft; - pcibr_info_h pcibr_infoh; - pcibr_info_t pcibr_info; - int func; - vertex_hdl_t conn_vhdl = GRAPH_VERTEX_NONE; - int nfunc; - int error_func; - int error_slot = 0; - int error = ENODEV; - - pcibr_soft = pcibr_soft_get(pcibr_vhdl); - - if (!pcibr_soft) - return -EINVAL; - - if (!PCIBR_VALID_SLOT(pcibr_soft, slot)) - return -EINVAL; - - if (pcibr_soft->bs_slot[slot].has_host) - return -EPERM; - - nfunc = pcibr_soft->bs_slot[slot].bss_ninfo; - pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; - - for (func = 0; func < nfunc; ++func) { - - pcibr_info = pcibr_infoh[func]; - - if (!pcibr_info) - continue; - - if (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) - continue; - - if (IS_PCIX(pcibr_soft) && pcibr_info->f_pcix_cap) { - int max_out; - - pcibr_soft->bs_pcix_num_funcs--; - max_out = pcibr_info->f_pcix_cap->pcix_type0_status.max_out_split; - pcibr_soft->bs_pcix_split_tot -= max_splittrans_to_numbuf[max_out]; - } - - conn_vhdl = pcibr_info->f_vertex; - - error_func = pciio_device_detach(conn_vhdl, drv_flags); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_DEV_DETACH, pcibr_vhdl, - "pcibr_slot_call_device_detach: slot=%d, func=%d " - "drv_flags=0x%x, pciio_device_detach returned %d\n", - PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), func, - drv_flags, error_func)); - - pcibr_info->f_att_det_error = error_func; - - if (error_func) - error_slot = error_func; - - error = error_slot; - - } /* next func */ - -#ifdef CONFIG_HOTPLUG_PCI_SGI - if (error) { - if ((error != ENODEV) && (error != EUNATCH) && (error != EPERM)) { - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_INCMPLT; - } - } else { - if (conn_vhdl != GRAPH_VERTEX_NONE) - pcibr_device_unregister(conn_vhdl); - pcibr_soft->bs_slot[slot].slot_status &= ~SLOT_STATUS_MASK; - pcibr_soft->bs_slot[slot].slot_status |= SLOT_SHUTDOWN_CMPLT; - } -#endif /* CONFIG_HOTPLUG_PCI_SGI */ - return error; -} - - - -/* - * pcibr_slot_detach - * This is a place holder routine to keep track of all the - * slot-specific freeing that needs to be done. - */ -int -pcibr_slot_detach(vertex_hdl_t pcibr_vhdl, - pciio_slot_t slot, - int drv_flags, - char *l1_msg, - int *sub_errorp) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - int error; - - /* Call the device detach function */ - error = (pcibr_slot_call_device_detach(pcibr_vhdl, slot, drv_flags)); - if (error) { - if (sub_errorp) - *sub_errorp = error; - if (l1_msg) - ; - return PCI_SLOT_DRV_DETACH_ERR; - } - - /* Recalculate the RBARs for all the devices on the bus since we've - * just freed some up and some of the devices could use them. - */ - if (IS_PCIX(pcibr_soft)) { - int tmp_slot; - - pcibr_soft->bs_pcix_rbar_inuse = 0; - pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; - pcibr_soft->bs_pcix_rbar_percent_allowed = - pcibr_pcix_rbars_calc(pcibr_soft); - - for (tmp_slot = pcibr_soft->bs_min_slot; - tmp_slot < PCIBR_NUM_SLOTS(pcibr_soft); ++tmp_slot) - (void)pcibr_slot_pcix_rbar_init(pcibr_soft, tmp_slot); - } - - return 0; - -} - -/* - * pcibr_probe_slot_pic: read a config space word - * while trapping any errors; return zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -static int -pcibr_probe_slot(pcibr_soft_t pcibr_soft, - cfg_p cfg, - unsigned *valp) -{ - return pcibr_probe_work(pcibr_soft, (void *)cfg, 4, (void *)valp); -} - -/* - * Probe an offset within a piomap with errors disabled. - * len must be 1, 2, 4, or 8. The probed address must be a multiple of - * len. - * - * Returns: 0 if the offset was probed and put valid data in valp - * -1 if there was a usage error such as improper alignment - * or out of bounds offset/len combination. In this - * case, the map was not probed - * 1 if the offset was probed but resulted in an error - * such as device not responding, bus error, etc. - */ - -int -pcibr_piomap_probe(pcibr_piomap_t piomap, off_t offset, int len, void *valp) -{ - if (offset + len > piomap->bp_mapsz) { - return -1; - } - - return pcibr_probe_work(piomap->bp_soft, - piomap->bp_kvaddr + offset, len, valp); -} - -static uint64_t -pcibr_disable_mst_timeout(pcibr_soft_t pcibr_soft) -{ - uint64_t old_enable; - uint64_t new_enable; - uint64_t intr_bits; - - intr_bits = PIC_ISR_PCI_MST_TIMEOUT - | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; - old_enable = pcireg_intr_enable_get(pcibr_soft); - pcireg_intr_enable_bit_clr(pcibr_soft, intr_bits); - new_enable = pcireg_intr_enable_get(pcibr_soft); - - if (old_enable == new_enable) { - return 0; /* was already disabled */ - } else { - return 1; - } -} - -static int -pcibr_enable_mst_timeout(pcibr_soft_t pcibr_soft) -{ - uint64_t old_enable; - uint64_t new_enable; - uint64_t intr_bits; - - intr_bits = PIC_ISR_PCI_MST_TIMEOUT - | PIC_ISR_PCIX_MTOUT | PIC_ISR_PCIX_SPLIT_EMSG; - old_enable = pcireg_intr_enable_get(pcibr_soft); - pcireg_intr_enable_bit_set(pcibr_soft, intr_bits); - new_enable = pcireg_intr_enable_get(pcibr_soft); - - if (old_enable == new_enable) { - return 0; /* was alread enabled */ - } else { - return 1; - } -} - -/* - * pcibr_probe_slot: read a config space word - * while trapping any errors; return zero if - * all went OK, or nonzero if there was an error. - * The value read, if any, is passed back - * through the valp parameter. - */ -static int -pcibr_probe_work(pcibr_soft_t pcibr_soft, - void *addr, - int len, - void *valp) -{ - int rv, changed; - - /* - * Sanity checks ... - */ - - if (len != 1 && len != 2 && len != 4 && len != 8) { - return -1; /* invalid len */ - } - - if ((uint64_t)addr & (len-1)) { - return -1; /* invalid alignment */ - } - - changed = pcibr_disable_mst_timeout(pcibr_soft); - - rv = snia_badaddr_val((void *)addr, len, valp); - - /* Clear the int_view register incase it was set */ - pcireg_intr_reset_set(pcibr_soft, BRIDGE_IRR_MULTI_CLR); - - if (changed) { - pcibr_enable_mst_timeout(pcibr_soft); - } - return (rv ? 1 : 0); /* return 1 for snia_badaddr_val error, 0 if ok */ -} - -void -pcibr_device_info_free(vertex_hdl_t pcibr_vhdl, pciio_slot_t slot) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - pcibr_info_t pcibr_info; - pciio_function_t func; - pcibr_soft_slot_t slotp = &pcibr_soft->bs_slot[slot]; - cfg_p cfgw; - int nfunc = slotp->bss_ninfo; - int bar; - int devio_index; - unsigned long s; - unsigned cmd_reg; - - - for (func = 0; func < nfunc; func++) { - pcibr_info = slotp->bss_infos[func]; - - if (!pcibr_info) - continue; - - s = pcibr_lock(pcibr_soft); - - /* Disable memory and I/O BARs */ - cfgw = pcibr_func_config_addr(pcibr_soft, 0, slot, func, 0); - cmd_reg = do_pcibr_config_get(cfgw, PCI_CFG_COMMAND, 4); - cmd_reg &= (PCI_CMD_MEM_SPACE | PCI_CMD_IO_SPACE); - do_pcibr_config_set(cfgw, PCI_CFG_COMMAND, 4, cmd_reg); - - for (bar = 0; bar < PCI_CFG_BASE_ADDRS; bar++) { - if (pcibr_info->f_window[bar].w_space == PCIIO_SPACE_NONE) - continue; - - /* Free the PCI bus space */ - pcibr_bus_addr_free(&pcibr_info->f_window[bar]); - - /* Get index of the DevIO(x) register used to access this BAR */ - devio_index = pcibr_info->f_window[bar].w_devio_index; - - - /* On last use, clear the DevIO(x) used to access this BAR */ - if (! --pcibr_soft->bs_slot[devio_index].bss_devio.bssd_ref_cnt) { - pcibr_soft->bs_slot[devio_index].bss_devio.bssd_space = - PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[devio_index].bss_devio.bssd_base = - PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_slot[devio_index].bss_device = 0; - } - } - - /* Free the Expansion ROM PCI bus space */ - if(pcibr_info->f_rbase && pcibr_info->f_rsize) { - pcibr_bus_addr_free(&pcibr_info->f_rwindow); - } - - pcibr_unlock(pcibr_soft, s); - - slotp->bss_infos[func] = 0; - pciio_device_info_unregister(pcibr_vhdl, &pcibr_info->f_c); - pciio_device_info_free(&pcibr_info->f_c); - - kfree(pcibr_info); - } - - /* Reset the mapping usage counters */ - slotp->bss_pmu_uctr = 0; - slotp->bss_d32_uctr = 0; - slotp->bss_d64_uctr = 0; - - /* Clear the Direct translation info */ - slotp->bss_d64_base = PCIBR_D64_BASE_UNSET; - slotp->bss_d64_flags = 0; - slotp->bss_d32_base = PCIBR_D32_BASE_UNSET; - slotp->bss_d32_flags = 0; -} - - -iopaddr_t -pcibr_bus_addr_alloc(pcibr_soft_t pcibr_soft, pciio_win_info_t win_info_p, - pciio_space_t space, int start, int size, int align) -{ - pciio_win_map_t win_map_p; - struct resource *root_resource = NULL; - iopaddr_t iopaddr = 0; - - switch (space) { - - case PCIIO_SPACE_IO: - win_map_p = &pcibr_soft->bs_io_win_map; - root_resource = &pcibr_soft->bs_io_win_root_resource; - break; - - case PCIIO_SPACE_MEM: - win_map_p = &pcibr_soft->bs_swin_map; - root_resource = &pcibr_soft->bs_swin_root_resource; - break; - - case PCIIO_SPACE_MEM32: - win_map_p = &pcibr_soft->bs_mem_win_map; - root_resource = &pcibr_soft->bs_mem_win_root_resource; - break; - - default: - return 0; - - } - iopaddr = pciio_device_win_alloc(root_resource, - win_info_p - ? &win_info_p->w_win_alloc - : NULL, - start, size, align); - return iopaddr; -} - - -void -pcibr_bus_addr_free(pciio_win_info_t win_info_p) -{ - pciio_device_win_free(&win_info_p->w_win_alloc); -} - -/* - * given a vertex_hdl to the pcibr_vhdl, return the brick's bus number - * associated with that vertex_hdl. The true mapping happens from the - * io_brick_tab[] array defined in ml/SN/iograph.c - */ -int -pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl) -{ - pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); - xwidgetnum_t widget = pcibr_soft->bs_xid; - int bricktype = pcibr_soft->bs_bricktype; - int bus; - - if ((bus = io_brick_map_widget(bricktype, widget)) <= 0) { - printk(KERN_WARNING "pcibr_widget_to_bus() bad bricktype %d\n", bricktype); - return 0; - } - - /* For PIC there are 2 busses per widget and pcibr_soft->bs_busnum - * will be 0 or 1. Add in the correct PIC bus offset. - */ - bus += pcibr_soft->bs_busnum; - return bus; -} diff --git a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c deleted file mode 100644 index dfae6b530..000000000 --- a/arch/ia64/sn/io/sn2/pciio.c +++ /dev/null @@ -1,1004 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include - -char pciio_info_fingerprint[] = "pciio_info"; - -/* ===================================================================== - * PCI Generic Bus Provider - * Implement PCI provider operations. The pciio* layer provides a - * platform-independent interface for PCI devices. This layer - * switches among the possible implementations of a PCI adapter. - */ - -/* ===================================================================== - * Provider Function Location - * - * If there is more than one possible provider for - * this platform, we need to examine the master - * vertex of the current vertex for a provider - * function structure, and indirect through the - * appropriately named member. - */ - -pciio_provider_t * -pciio_to_provider_fns(vertex_hdl_t dev) -{ - pciio_info_t card_info; - pciio_provider_t *provider_fns; - - /* - * We're called with two types of vertices, one is - * the bridge vertex (ends with "pci") and the other is the - * pci slot vertex (ends with "pci/[0-8]"). For the first type - * we need to get the provider from the PFUNCS label. For - * the second we get it from fastinfo/c_pops. - */ - provider_fns = pciio_provider_fns_get(dev); - if (provider_fns == NULL) { - card_info = pciio_info_get(dev); - if (card_info != NULL) { - provider_fns = pciio_info_pops_get(card_info); - } - } - - if (provider_fns == NULL) { - char devname[MAXDEVNAME]; - panic("%s: provider_fns == NULL", vertex_to_name(dev, devname, MAXDEVNAME)); - } - return provider_fns; - -} - -#define DEV_FUNC(dev,func) pciio_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((pciio_piomap_t)(x)) -#define CAST_DMAMAP(x) ((pciio_dmamap_t)(x)) -#define CAST_INTR(x) ((pciio_intr_t)(x)) - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC((map)->pp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC((map)->pd_dev,func) -#define INTR_FUNC(intr_hdl,func) DEV_FUNC((intr_hdl)->pi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * pciio space on a specified card - */ - -pciio_piomap_t -pciio_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* lowest address (or offset in window) */ - size_t byte_count, /* size of region containing our mappings */ - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (pciio_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, space, addr, byte_count, byte_count_max, flags); -} - -void -pciio_piomap_free(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_free) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piomap_addr(pciio_piomap_t pciio_piomap, /* mapping resources */ - iopaddr_t pciio_addr, /* map for this pciio address */ - size_t byte_count) -{ /* map this many bytes */ - pciio_piomap->pp_kvaddr = PIOMAP_FUNC(pciio_piomap, piomap_addr) - (CAST_PIOMAP(pciio_piomap), pciio_addr, byte_count); - - return pciio_piomap->pp_kvaddr; -} - -void -pciio_piomap_done(pciio_piomap_t pciio_piomap) -{ - PIOMAP_FUNC(pciio_piomap, piomap_done) - (CAST_PIOMAP(pciio_piomap)); -} - -caddr_t -pciio_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, space, addr, byte_count, flags); -} - -caddr_t -pciio_pio_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_space_t space, /* CFG, MEM, IO, or a device-decoded window */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - pciio_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - pciio_piomap_t map = 0; - int errfree = 0; - caddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_piotrans_addr - (dev, dev_desc, space, addr, byte_count, flags); - if (res) - return res; /* pciio_piotrans worked */ - - if (!map) { - map = pciio_piomap_alloc - (dev, dev_desc, space, addr, byte_count, byte_count, flags); - if (!map) - return res; /* pciio_piomap_alloc failed */ - errfree = 1; - } - - res = pciio_piomap_addr - (map, addr, byte_count); - if (!res) { - if (errfree) - pciio_piomap_free(map); - return res; /* pciio_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_piomap_addr succeeded */ -} - -iopaddr_t -pciio_piospace_alloc(vertex_hdl_t dev, /* Device requiring space */ - device_desc_t dev_desc, /* Device descriptor */ - pciio_space_t space, /* MEM32/MEM64/IO */ - size_t byte_count, /* Size of mapping */ - size_t align) -{ /* Alignment needed */ - if (align < PAGE_SIZE) - align = PAGE_SIZE; - return DEV_FUNC(dev, piospace_alloc) - (dev, dev_desc, space, byte_count, align); -} - -void -pciio_piospace_free(vertex_hdl_t dev, /* Device freeing space */ - pciio_space_t space, /* Type of space */ - iopaddr_t pciaddr, /* starting address */ - size_t byte_count) -{ /* Range of address */ - DEV_FUNC(dev, piospace_free) - (dev, space, pciaddr, byte_count); -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from pci space to system - * physical space. - */ - -pciio_dmamap_t -pciio_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (pciio_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - -void -pciio_dmamap_free(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_free) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmamap_addr(pciio_dmamap_t pciio_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(pciio_dmamap, dmamap_addr) - (CAST_DMAMAP(pciio_dmamap), paddr, byte_count); -} - -void -pciio_dmamap_done(pciio_dmamap_t pciio_dmamap) -{ - DMAMAP_FUNC(pciio_dmamap, dmamap_done) - (CAST_DMAMAP(pciio_dmamap)); -} - -iopaddr_t -pciio_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - -iopaddr_t -pciio_dma_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - pciio_dmamap_t *mapp, /* map to use, then map we used */ - unsigned flags) -{ /* PIO flags */ - pciio_dmamap_t map = 0; - int errfree = 0; - iopaddr_t res; - - if (mapp) { - map = *mapp; /* possible pre-allocated map */ - *mapp = 0; /* record "no map used" */ - } - - res = pciio_dmatrans_addr - (dev, dev_desc, paddr, byte_count, flags); - if (res) - return res; /* pciio_dmatrans worked */ - - if (!map) { - map = pciio_dmamap_alloc - (dev, dev_desc, byte_count, flags); - if (!map) - return res; /* pciio_dmamap_alloc failed */ - errfree = 1; - } - - res = pciio_dmamap_addr - (map, paddr, byte_count); - if (!res) { - if (errfree) - pciio_dmamap_free(map); - return res; /* pciio_dmamap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* pciio_dmamap_addr succeeded */ -} - -void -pciio_dmamap_drain(pciio_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -pciio_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow crosstalk devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -pciio_intr_t -pciio_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - pciio_intr_line_t lines, /* INTR line(s) to attach */ - vertex_hdl_t owner_dev) -{ /* owner of this interrupt */ - return (pciio_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, lines, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -pciio_intr_free(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - -/* - * Associate resources allocated with a previous pciio_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -pciio_intr_connect(pciio_intr_t intr_hdl, - intr_func_t intr_func, intr_arg_t intr_arg) /* pciio intr resource handle */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), intr_func, intr_arg); -} - -/* - * Disassociate handler with the specified interrupt. - */ -void -pciio_intr_disconnect(pciio_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -vertex_hdl_t -pciio_intr_cpu_get(pciio_intr_t intr_hdl) -{ - return INTR_FUNC(intr_hdl, intr_cpu_get) - (CAST_INTR(intr_hdl)); -} - -void -pciio_slot_func_to_name(char *name, - pciio_slot_t slot, - pciio_function_t func) -{ - /* - * standard connection points: - * - * PCIIO_SLOT_NONE: .../pci/direct - * PCIIO_FUNC_NONE: .../pci/ ie. .../pci/3 - * multifunction: .../pci/ ie. .../pci/3c - */ - - if (slot == PCIIO_SLOT_NONE) - sprintf(name, EDGE_LBL_DIRECT); - else if (func == PCIIO_FUNC_NONE) - sprintf(name, "%d", slot); - else - sprintf(name, "%d%c", slot, 'a'+func); -} - -/* - * pciio_cardinfo_get - * - * Get the pciio info structure corresponding to the - * specified PCI "slot" (we like it when the same index - * number is used for the PCI IDSEL, the REQ/GNT pair, - * and the interrupt line being used for INTA. We like - * it so much we call it the slot number). - */ -static pciio_info_t -pciio_cardinfo_get( - vertex_hdl_t pciio_vhdl, - pciio_slot_t pci_slot) -{ - char namebuf[16]; - pciio_info_t info = 0; - vertex_hdl_t conn; - - pciio_slot_func_to_name(namebuf, pci_slot, PCIIO_FUNC_NONE); - if (GRAPH_SUCCESS == - hwgraph_traverse(pciio_vhdl, namebuf, &conn)) { - info = pciio_info_chk(conn); - hwgraph_vertex_unref(conn); - } - - return info; -} - - -/* - * pciio_error_handler: - * dispatch an error to the appropriate - * pciio connection point, or process - * it as a generic pci error. - * Yes, the first parameter is the - * provider vertex at the middle of - * the bus; we get to the pciio connect - * point using the ioerror widgetdev field. - * - * This function is called by the - * specific PCI provider, after it has figured - * out where on the PCI bus (including which slot, - * if it can tell) the error came from. - */ -/*ARGSUSED */ -int -pciio_error_handler( - vertex_hdl_t pciio_vhdl, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - pciio_info_t pciio_info; - vertex_hdl_t pconn_vhdl; - pciio_slot_t slot; - - int retval; - -#if DEBUG && ERROR_DEBUG - printk("%v: pciio_error_handler\n", pciio_vhdl); -#endif - - IOERR_PRINTF(printk(KERN_NOTICE "%v: PCI Bus Error: Error code: %d Error mode: %d\n", - pciio_vhdl, error_code, mode)); - - /* If there is an error handler sitting on - * the "no-slot" connection point, give it - * first crack at the error. NOTE: it is - * quite possible that this function may - * do further refining of the ioerror. - */ - pciio_info = pciio_cardinfo_get(pciio_vhdl, PCIIO_SLOT_NONE); - if (pciio_info && pciio_info->c_efunc) { - pconn_vhdl = pciio_info_dev_get(pciio_info); - - retval = pciio_info->c_efunc - (pciio_info->c_einfo, error_code, mode, ioerror); - if (retval != IOERROR_UNHANDLED) - return retval; - } - - /* Is the error associated with a particular slot? - */ - if (IOERROR_FIELDVALID(ioerror, widgetdev)) { - short widgetdev; - /* - * NOTE : - * widgetdev is a 4byte value encoded as slot in the higher order - * 2 bytes and function in the lower order 2 bytes. - */ - IOERROR_GETVALUE(widgetdev, ioerror, widgetdev); - slot = pciio_widgetdev_slot_get(widgetdev); - - /* If this slot has an error handler, - * deliver the error to it. - */ - pciio_info = pciio_cardinfo_get(pciio_vhdl, slot); - if (pciio_info != NULL) { - if (pciio_info->c_efunc != NULL) { - - pconn_vhdl = pciio_info_dev_get(pciio_info); - - retval = pciio_info->c_efunc - (pciio_info->c_einfo, error_code, mode, ioerror); - if (retval != IOERROR_UNHANDLED) - return retval; - } - } - } - - return (mode == MODE_DEVPROBE) - ? IOERROR_HANDLED /* probes are OK */ - : IOERROR_UNHANDLED; /* otherwise, foo! */ -} - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup a crosstalk provider - */ -void -pciio_provider_startup(vertex_hdl_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_startup) - (pciio_provider); -} - -/* - * Shutdown a crosstalk provider - */ -void -pciio_provider_shutdown(vertex_hdl_t pciio_provider) -{ - DEV_FUNC(pciio_provider, provider_shutdown) - (pciio_provider); -} - -/* - * Read value of configuration register - */ -uint64_t -pciio_config_get(vertex_hdl_t dev, - unsigned reg, - unsigned size) -{ - uint64_t value = 0; - unsigned shift = 0; - - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - value |= DEV_FUNC(dev, config_get) - (dev, reg, biw) << shift; - - shift += 8*biw; - reg += biw; - size -= biw; - } - return value; -} - -/* - * Change value of configuration register - */ -void -pciio_config_set(vertex_hdl_t dev, - unsigned reg, - unsigned size, - uint64_t value) -{ - /* handle accesses that cross words here, - * since that's common code between all - * possible providers. - */ - while (size > 0) { - unsigned biw = 4 - (reg&3); - if (biw > size) - biw = size; - - DEV_FUNC(dev, config_set) - (dev, reg, biw, value); - reg += biw; - size -= biw; - value >>= biw * 8; - } -} - -/* ===================================================================== - * GENERIC PCI SUPPORT FUNCTIONS - */ - -/* - * Issue a hardware reset to a card. - */ -int -pciio_reset(vertex_hdl_t dev) -{ - return DEV_FUNC(dev, reset) (dev); -} - -/****** Generic pci slot information interfaces ******/ - -pciio_info_t -pciio_info_chk(vertex_hdl_t pciio) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(pciio, INFO_LBL_PCIIO, &ainfo); - return (pciio_info_t) ainfo; -} - -pciio_info_t -pciio_info_get(vertex_hdl_t pciio) -{ - pciio_info_t pciio_info; - - pciio_info = (pciio_info_t) hwgraph_fastinfo_get(pciio); - - if ((pciio_info != NULL) && - (pciio_info->c_fingerprint != pciio_info_fingerprint) - && (pciio_info->c_fingerprint != NULL)) { - - return((pciio_info_t)-1); /* Should panic .. */ - } - - return pciio_info; -} - -void -pciio_info_set(vertex_hdl_t pciio, pciio_info_t pciio_info) -{ - if (pciio_info != NULL) - pciio_info->c_fingerprint = pciio_info_fingerprint; - hwgraph_fastinfo_set(pciio, (arbitrary_info_t) pciio_info); - - /* Also, mark this vertex as a PCI slot - * and use the pciio_info, so pciio_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(pciio, INFO_LBL_PCIIO, - (arbitrary_info_t) pciio_info); -} - -vertex_hdl_t -pciio_info_dev_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vertex); -} - -/*ARGSUSED*/ -pciio_bus_t -pciio_info_bus_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_bus); -} - -pciio_slot_t -pciio_info_slot_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_slot); -} - -pciio_function_t -pciio_info_function_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_func); -} - -pciio_vendor_id_t -pciio_info_vendor_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_vendor); -} - -pciio_device_id_t -pciio_info_device_id_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_device); -} - -vertex_hdl_t -pciio_info_master_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_master); -} - -arbitrary_info_t -pciio_info_mfast_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_mfast); -} - -pciio_provider_t * -pciio_info_pops_get(pciio_info_t pciio_info) -{ - return (pciio_info->c_pops); -} - -/* ===================================================================== - * GENERIC PCI INITIALIZATION FUNCTIONS - */ - -/* - * pciioattach: called for each vertex in the graph - * that is a PCI provider. - */ -/*ARGSUSED */ -int -pciio_attach(vertex_hdl_t pciio) -{ -#if DEBUG && ATTACH_DEBUG - char devname[MAXDEVNAME]; - printk("%s: pciio_attach\n", vertex_to_name(pciio, devname, MAXDEVNAME)); -#endif - return 0; -} - -/* - * Associate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_register(vertex_hdl_t provider, pciio_provider_t *pciio_fns) -{ - hwgraph_info_add_LBL(provider, INFO_LBL_PFUNCS, (arbitrary_info_t) pciio_fns); -} - -/* - * Disassociate a set of pciio_provider functions with a vertex. - */ -void -pciio_provider_unregister(vertex_hdl_t provider) -{ - arbitrary_info_t ainfo; - - hwgraph_info_remove_LBL(provider, INFO_LBL_PFUNCS, (long *) &ainfo); -} - -/* - * Obtain a pointer to the pciio_provider functions for a specified Crosstalk - * provider. - */ -pciio_provider_t * -pciio_provider_fns_get(vertex_hdl_t provider) -{ - arbitrary_info_t ainfo = 0; - - (void) hwgraph_info_get_LBL(provider, INFO_LBL_PFUNCS, &ainfo); - return (pciio_provider_t *) ainfo; -} - -pciio_info_t -pciio_device_info_new( - pciio_info_t pciio_info, - vertex_hdl_t master, - pciio_slot_t slot, - pciio_function_t func, - pciio_vendor_id_t vendor_id, - pciio_device_id_t device_id) -{ - if (!pciio_info) { - pciio_info = kmalloc(sizeof (*(pciio_info)), GFP_KERNEL); - if ( pciio_info ) - memset(pciio_info, 0, sizeof (*(pciio_info))); - else { - printk(KERN_WARNING "pciio_device_info_new(): Unable to " - "allocate memory\n"); - return NULL; - } - } - pciio_info->c_slot = slot; - pciio_info->c_func = func; - pciio_info->c_vendor = vendor_id; - pciio_info->c_device = device_id; - pciio_info->c_master = master; - pciio_info->c_mfast = hwgraph_fastinfo_get(master); - pciio_info->c_pops = pciio_provider_fns_get(master); - pciio_info->c_efunc = 0; - pciio_info->c_einfo = 0; - - return pciio_info; -} - -void -pciio_device_info_free(pciio_info_t pciio_info) -{ - /* NOTE : pciio_info is a structure within the pcibr_info - * and not a pointer to memory allocated on the heap !! - */ - memset((char *)pciio_info, 0, sizeof(pciio_info)); -} - -vertex_hdl_t -pciio_device_info_register( - vertex_hdl_t connectpt, /* vertex at center of bus */ - pciio_info_t pciio_info) /* details about the connectpt */ -{ - char name[32]; - vertex_hdl_t pconn; - int device_master_set(vertex_hdl_t, vertex_hdl_t); - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - if (GRAPH_SUCCESS != - hwgraph_path_add(connectpt, name, &pconn)) - return pconn; - - pciio_info->c_vertex = pconn; - pciio_info_set(pconn, pciio_info); - - /* - * create link to our pci provider - */ - - device_master_set(pconn, pciio_info->c_master); - return pconn; -} - -void -pciio_device_info_unregister(vertex_hdl_t connectpt, - pciio_info_t pciio_info) -{ - char name[32]; - vertex_hdl_t pconn = NULL; - - if (!pciio_info) - return; - - pciio_slot_func_to_name(name, - pciio_info->c_slot, - pciio_info->c_func); - - pciio_info_set(pconn,0); - - hwgraph_vertex_unref(pconn); - hwgraph_vertex_destroy(pconn); -} - -/*ARGSUSED */ -int -pciio_device_attach(vertex_hdl_t pconn, - int drv_flags) -{ - pciio_info_t pciio_info; - pciio_vendor_id_t vendor_id; - pciio_device_id_t device_id; - - - pciio_info = pciio_info_get(pconn); - - vendor_id = pciio_info->c_vendor; - device_id = pciio_info->c_device; - - /* we don't start attaching things until - * all the driver init routines (including - * pciio_init) have been called; so we - * can assume here that we have a registry. - */ - - return(cdl_add_connpt(vendor_id, device_id, pconn, drv_flags)); -} - -int -pciio_device_detach(vertex_hdl_t pconn, - int drv_flags) -{ - return(0); -} - -/* - * Allocate space from the specified PCI window mapping resource. On - * success record information about the allocation in the supplied window - * allocation cookie (if non-NULL) and return the address of the allocated - * window. On failure return NULL. - * - * The "size" parameter is usually from a PCI device's Base Address Register - * (BAR) decoder. As such, the allocation must be aligned to be a multiple of - * that. The "align" parameter acts as a ``minimum alignment'' allocation - * constraint. The alignment contraint reflects system or device addressing - * restrictions such as the inability to share higher level ``windows'' - * between devices, etc. The returned PCI address allocation will be a - * multiple of the alignment constraint both in alignment and size. Thus, the - * returned PCI address block is aligned to the maximum of the requested size - * and alignment. - */ -iopaddr_t -pciio_device_win_alloc(struct resource *root_resource, - pciio_win_alloc_t win_alloc, - size_t start, size_t size, size_t align) -{ - - struct resource *new_res; - int status; - - new_res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); - if (!new_res) - return 0; - - if (start > 0) { - status = allocate_resource( root_resource, new_res, - size, start /* Min start addr. */, - (start + size) - 1, 1, - NULL, NULL); - } else { - if (size > align) - align = size; - status = allocate_resource( root_resource, new_res, - size, align /* Min start addr. */, - root_resource->end, align, - NULL, NULL); - } - - if (status) { - kfree(new_res); - return((iopaddr_t) NULL); - } - - /* - * If a window allocation cookie has been supplied, use it to keep - * track of all the allocated space assigned to this window. - */ - if (win_alloc) { - win_alloc->wa_resource = new_res; - win_alloc->wa_base = new_res->start; - win_alloc->wa_pages = size; - } - - return new_res->start; -} - -/* - * Free the specified window allocation back into the PCI window mapping - * resource. As noted above, we keep page addresses offset by 1 ... - */ -void -pciio_device_win_free(pciio_win_alloc_t win_alloc) -{ - int status; - - if (win_alloc->wa_resource) { - status = release_resource(win_alloc->wa_resource); - if (!status) - kfree(win_alloc->wa_resource); - else - BUG(); - } -} - -/* - * pciio_error_register: - * arrange for a function to be called with - * a specified first parameter plus other - * information when an error is encountered - * and traced to the pci slot corresponding - * to the connection point pconn. - * - * may also be called with a null function - * pointer to "unregister" the error handler. - * - * NOTE: subsequent calls silently overwrite - * previous data for this vertex. We assume that - * cooperating drivers, well, cooperate ... - */ -void -pciio_error_register(vertex_hdl_t pconn, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - pciio_info_t pciio_info; - - pciio_info = pciio_info_get(pconn); - ASSERT(pciio_info != NULL); - pciio_info->c_efunc = efunc; - pciio_info->c_einfo = einfo; -} - -/* - * Check if any device has been found in this slot, and return - * true or false - * vhdl is the vertex for the slot - */ -int -pciio_slot_inuse(vertex_hdl_t pconn_vhdl) -{ - pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); - - ASSERT(pciio_info); - ASSERT(pciio_info->c_vertex == pconn_vhdl); - if (pciio_info->c_vendor) { - /* - * Non-zero value for vendor indicate - * a board being found in this slot. - */ - return 1; - } - return 0; -} - -int -pciio_info_type1_get(pciio_info_t pci_info) -{ - return (pci_info->c_type1); -} diff --git a/arch/ia64/sn/io/sn2/pic.c b/arch/ia64/sn/io/sn2/pic.c deleted file mode 100644 index c9cea08d4..000000000 --- a/arch/ia64/sn/io/sn2/pic.c +++ /dev/null @@ -1,835 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct file_operations pcibr_fops; -extern pcibr_list_p pcibr_list; - -static int pic_attach2(vertex_hdl_t, void *, vertex_hdl_t, - int, pcibr_soft_t *); - -extern int isIO9(nasid_t); -extern char *dev_to_name(vertex_hdl_t dev, char *buf, uint buflen); -extern int pcibr_widget_to_bus(vertex_hdl_t pcibr_vhdl); -extern pcibr_hints_t pcibr_hints_get(vertex_hdl_t, int); -extern unsigned pcibr_intr_bits(pciio_info_t info, - pciio_intr_line_t lines, int nslots); -extern void pcibr_setwidint(xtalk_intr_t); -extern int pcibr_error_handler_wrapper(error_handler_arg_t, int, - ioerror_mode_t, ioerror_t *); -extern void pcibr_error_intr_handler(intr_arg_t); -extern void pcibr_directmap_init(pcibr_soft_t); -extern int pcibr_slot_info_init(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_addr_space_init(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_device_init(vertex_hdl_t, pciio_slot_t); -extern int pcibr_slot_pcix_rbar_init(pcibr_soft_t, pciio_slot_t); -extern int pcibr_slot_guest_info_init(vertex_hdl_t,pciio_slot_t); -extern int pcibr_slot_call_device_attach(vertex_hdl_t, - pciio_slot_t, int); -extern void pcibr_rrb_alloc_init(pcibr_soft_t, int, int, int); -extern int pcibr_pcix_rbars_calc(pcibr_soft_t); -extern pcibr_info_t pcibr_device_info_new(pcibr_soft_t, pciio_slot_t, - pciio_function_t, pciio_vendor_id_t, - pciio_device_id_t); -extern int pcibr_initial_rrb(vertex_hdl_t, pciio_slot_t, - pciio_slot_t); -extern void xwidget_error_register(vertex_hdl_t, error_handler_f *, - error_handler_arg_t); -extern void pcibr_clearwidint(pcibr_soft_t); - - - -/* - * copy xwidget_info_t from conn_v to peer_conn_v - */ -static int -pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, - cnodeid_t xbow_peer, char *peer_path) -{ - xwidget_info_t widget_info, peer_widget_info; - vertex_hdl_t peer_hubv; - hubinfo_t peer_hub_info; - - /* get the peer hub's widgetid */ - peer_hubv = NODEPDA(xbow_peer)->node_vertex; - peer_hub_info = NULL; - hubinfo_get(peer_hubv, &peer_hub_info); - if (peer_hub_info == NULL) - return 0; - - if (hwgraph_info_get_LBL(conn_v, INFO_LBL_XWIDGET, - (arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) { - peer_widget_info = kmalloc(sizeof (*(peer_widget_info)), GFP_KERNEL); - if ( !peer_widget_info ) { - return -ENOMEM; - } - memset(peer_widget_info, 0, sizeof (*(peer_widget_info))); - - peer_widget_info->w_fingerprint = widget_info_fingerprint; - peer_widget_info->w_vertex = peer_conn_v; - peer_widget_info->w_id = widget_info->w_id; - peer_widget_info->w_master = peer_hubv; - peer_widget_info->w_masterid = peer_hub_info->h_widgetid; - /* structure copy */ - peer_widget_info->w_hwid = widget_info->w_hwid; - peer_widget_info->w_efunc = 0; - peer_widget_info->w_einfo = 0; - peer_widget_info->w_name = kmalloc(strlen(peer_path) + 1, GFP_KERNEL); - if (!peer_widget_info->w_name) { - kfree(peer_widget_info); - return -ENOMEM; - } - strcpy(peer_widget_info->w_name, peer_path); - - if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_XWIDGET, - (arbitrary_info_t)peer_widget_info) != GRAPH_SUCCESS) { - kfree(peer_widget_info->w_name); - kfree(peer_widget_info); - return 0; - } - - xwidget_info_set(peer_conn_v, peer_widget_info); - - return 1; - } - - printk("pic_bus1_widget_info_dup: " - "cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v); - return 0; -} - -/* - * If this PIC is attached to two Cbricks ("dual-ported") then - * attach each bus to opposite Cbricks. - * - * If successful, return a new vertex suitable for attaching the PIC bus. - * If not successful, return zero and both buses will attach to the - * vertex passed into pic_attach(). - */ -static vertex_hdl_t -pic_bus1_redist(nasid_t nasid, vertex_hdl_t conn_v) -{ - cnodeid_t cnode = nasid_to_cnodeid(nasid); - cnodeid_t xbow_peer = -1; - char pathname[256], peer_path[256], tmpbuf[256]; - char *p; - int rc; - vertex_hdl_t peer_conn_v, hubv; - int pos; - slabid_t slab; - - if (NODEPDA(cnode)->xbow_peer >= 0) { /* if dual-ported */ - /* create a path for this widget on the peer Cbrick */ - /* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */ - /* sprintf(pathname, "%v", conn_v); */ - xbow_peer = nasid_to_cnodeid(NODEPDA(cnode)->xbow_peer); - pos = hwgfs_generate_path(conn_v, tmpbuf, 256); - strcpy(pathname, &tmpbuf[pos]); - p = pathname + strlen("hw/module/001c01/slab/0/"); - - memset(tmpbuf, 0, 16); - format_module_id(tmpbuf, geo_module((NODEPDA(xbow_peer))->geoid), MODULE_FORMAT_BRIEF); - slab = geo_slab((NODEPDA(xbow_peer))->geoid); - sprintf(peer_path, "module/%s/slab/%d/%s", tmpbuf, (int)slab, p); - - /* Look for vertex for this widget on the peer Cbrick. - * Expect GRAPH_NOT_FOUND. - */ - rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v); - if (GRAPH_SUCCESS == rc) - printk("pic_attach: found unexpected vertex: 0x%lx\n", - (uint64_t)peer_conn_v); - else if (GRAPH_NOT_FOUND != rc) { - printk("pic_attach: hwgraph_traverse unexpectedly" - " returned 0x%x\n", rc); - } else { - /* try to add the widget vertex to the peer Cbrick */ - rc = hwgraph_path_add(hwgraph_root, peer_path, &peer_conn_v); - - if (GRAPH_SUCCESS != rc) - printk("pic_attach: hwgraph_path_add" - " failed with 0x%x\n", rc); - else { - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, - "pic_bus1_redist: added vertex %v\n", peer_conn_v)); - - /* Now hang appropiate stuff off of the new - * vertex. We bail out if we cannot add something. - * In that case, we don't remove the newly added - * vertex but that should be safe and we don't - * really expect the additions to fail anyway. - */ - if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, - xbow_peer, peer_path)) - return 0; - - hubv = cnodeid_to_vertex(xbow_peer); - ASSERT(hubv != GRAPH_VERTEX_NONE); - device_master_set(peer_conn_v, hubv); - xtalk_provider_register(hubv, &hub_provider); - xtalk_provider_startup(hubv); - return peer_conn_v; - } - } - } - return 0; -} - -/* - * PIC has two buses under a single widget. pic_attach() calls pic_attach2() - * to attach each of those buses. - */ -int -pic_attach(vertex_hdl_t conn_v) -{ - int rc; - void *bridge0, *bridge1 = (void *)0; - vertex_hdl_t pcibr_vhdl0, pcibr_vhdl1 = (vertex_hdl_t)0; - pcibr_soft_t bus0_soft, bus1_soft = (pcibr_soft_t)0; - vertex_hdl_t conn_v0, conn_v1, peer_conn_v; - int bricktype; - int iobrick_type_get_nasid(nasid_t nasid); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_attach()\n")); - - bridge0 = pcibr_bridge_ptr_get(conn_v, 0); - bridge1 = pcibr_bridge_ptr_get(conn_v, 1); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, - "pic_attach: bridge0=0x%lx, bridge1=0x%lx\n", - bridge0, bridge1)); - - conn_v0 = conn_v1 = conn_v; - - /* If dual-ported then split the two PIC buses across both Cbricks */ - peer_conn_v = pic_bus1_redist(NASID_GET(bridge0), conn_v); - if (peer_conn_v) - conn_v1 = peer_conn_v; - - /* - * Create the vertex for the PCI buses, which we - * will also use to hold the pcibr_soft and - * which will be the "master" vertex for all the - * pciio connection points we will hang off it. - * This needs to happen before we call nic_bridge_vertex_info - * as we are some of the *_vmc functions need access to the edges. - * - * Opening this vertex will provide access to - * the Bridge registers themselves. - */ - bricktype = iobrick_type_get_nasid(NASID_GET(bridge0)); - if ( bricktype == MODULE_CGBRICK ) { - rc = hwgraph_path_add(conn_v0, EDGE_LBL_AGP_0, &pcibr_vhdl0); - ASSERT(rc == GRAPH_SUCCESS); - rc = hwgraph_path_add(conn_v1, EDGE_LBL_AGP_1, &pcibr_vhdl1); - ASSERT(rc == GRAPH_SUCCESS); - } else { - rc = hwgraph_path_add(conn_v0, EDGE_LBL_PCIX_0, &pcibr_vhdl0); - ASSERT(rc == GRAPH_SUCCESS); - rc = hwgraph_path_add(conn_v1, EDGE_LBL_PCIX_1, &pcibr_vhdl1); - ASSERT(rc == GRAPH_SUCCESS); - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, - "pic_attach: pcibr_vhdl0=0x%lx, pcibr_vhdl1=0x%lx\n", - pcibr_vhdl0, pcibr_vhdl1)); - - /* register pci provider array */ - pciio_provider_register(pcibr_vhdl0, &pci_pic_provider); - pciio_provider_register(pcibr_vhdl1, &pci_pic_provider); - - pciio_provider_startup(pcibr_vhdl0); - pciio_provider_startup(pcibr_vhdl1); - - pic_attach2(conn_v0, bridge0, pcibr_vhdl0, 0, &bus0_soft); - pic_attach2(conn_v1, bridge1, pcibr_vhdl1, 1, &bus1_soft); - - { - /* If we're dual-ported finish duplicating the peer info structure. - * The error handler and arg are done in pic_attach2(). - */ - xwidget_info_t info0, info1; - if (conn_v0 != conn_v1) { /* dual ported */ - info0 = xwidget_info_get(conn_v0); - info1 = xwidget_info_get(conn_v1); - if (info1->w_efunc == (error_handler_f *)NULL) - info1->w_efunc = info0->w_efunc; - if (info1->w_einfo == (error_handler_arg_t)0) - info1->w_einfo = bus1_soft; - } - } - - /* save a pointer to the PIC's other bus's soft struct */ - bus0_soft->bs_peers_soft = bus1_soft; - bus1_soft->bs_peers_soft = bus0_soft; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, - "pic_attach: bus0_soft=0x%lx, bus1_soft=0x%lx\n", - bus0_soft, bus1_soft)); - - return 0; -} - - -/* - * PIC has two buses under a single widget. pic_attach() calls pic_attach2() - * to attach each of those buses. - */ -static int -pic_attach2(vertex_hdl_t xconn_vhdl, void *bridge, - vertex_hdl_t pcibr_vhdl, int busnum, pcibr_soft_t *ret_softp) -{ - vertex_hdl_t ctlr_vhdl; - pcibr_soft_t pcibr_soft; - pcibr_info_t pcibr_info; - xwidget_info_t info; - xtalk_intr_t xtalk_intr; - pcibr_list_p self; - int entry, slot, ibit, i; - vertex_hdl_t noslot_conn; - char devnm[MAXDEVNAME], *s; - pcibr_hints_t pcibr_hints; - picreg_t id; - picreg_t int_enable; - picreg_t pic_ctrl_reg; - - int iobrick_type_get_nasid(nasid_t nasid); - int iomoduleid_get(nasid_t nasid); - int irq; - int cpu; - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pic_attach2: bridge=0x%lx, busnum=%d\n", bridge, busnum)); - - ctlr_vhdl = NULL; - ctlr_vhdl = hwgraph_register(pcibr_vhdl, EDGE_LBL_CONTROLLER, 0, - 0, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - (struct file_operations *)&pcibr_fops, (void *)pcibr_vhdl); - ASSERT(ctlr_vhdl != NULL); - - id = pcireg_bridge_id_get(bridge); - hwgraph_info_add_LBL(pcibr_vhdl, INFO_LBL_PCIBR_ASIC_REV, - (arbitrary_info_t)XWIDGET_PART_REV_NUM(id)); - - /* - * Get the hint structure; if some NIC callback marked this vertex as - * "hands-off" then we just return here, before doing anything else. - */ - pcibr_hints = pcibr_hints_get(xconn_vhdl, 0); - - if (pcibr_hints && pcibr_hints->ph_hands_off) - return -1; - - /* allocate soft structure to hang off the vertex. Link the new soft - * structure to the pcibr_list linked list - */ - pcibr_soft = kmalloc(sizeof (*(pcibr_soft)), GFP_KERNEL); - if ( !pcibr_soft ) - return -ENOMEM; - - self = kmalloc(sizeof (*(self)), GFP_KERNEL); - if ( !self ) { - kfree(pcibr_soft); - return -ENOMEM; - } - memset(pcibr_soft, 0, sizeof (*(pcibr_soft))); - memset(self, 0, sizeof (*(self))); - - self->bl_soft = pcibr_soft; - self->bl_vhdl = pcibr_vhdl; - self->bl_next = pcibr_list; - pcibr_list = self; - - if (ret_softp) - *ret_softp = pcibr_soft; - - memset(pcibr_soft, 0, sizeof *pcibr_soft); - pcibr_soft_set(pcibr_vhdl, pcibr_soft); - - s = dev_to_name(pcibr_vhdl, devnm, MAXDEVNAME); - pcibr_soft->bs_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - if (!pcibr_soft->bs_name) - return -ENOMEM; - - strcpy(pcibr_soft->bs_name, s); - - pcibr_soft->bs_conn = xconn_vhdl; - pcibr_soft->bs_vhdl = pcibr_vhdl; - pcibr_soft->bs_base = (void *)bridge; - pcibr_soft->bs_rev_num = XWIDGET_PART_REV_NUM(id); - pcibr_soft->bs_intr_bits = (pcibr_intr_bits_f *)pcibr_intr_bits; - pcibr_soft->bsi_err_intr = 0; - pcibr_soft->bs_min_slot = 0; - pcibr_soft->bs_max_slot = 3; - pcibr_soft->bs_busnum = busnum; - pcibr_soft->bs_bridge_type = PCIBR_BRIDGETYPE_PIC; - pcibr_soft->bs_int_ate_size = PIC_INTERNAL_ATES; - /* Make sure this is called after setting the bs_base and bs_bridge_type */ - pcibr_soft->bs_bridge_mode = (pcireg_speed_get(pcibr_soft) << 1) | - pcireg_mode_get(pcibr_soft); - - info = xwidget_info_get(xconn_vhdl); - pcibr_soft->bs_xid = xwidget_info_id_get(info); - pcibr_soft->bs_master = xwidget_info_master_get(info); - pcibr_soft->bs_mxid = xwidget_info_masterid_get(info); - - strcpy(pcibr_soft->bs_asic_name, "PIC"); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pic_attach2: pcibr_soft=0x%lx, mode=0x%x\n", - pcibr_soft, pcibr_soft->bs_bridge_mode)); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pic_attach2: %s ASIC: rev %s (code=0x%x)\n", - pcibr_soft->bs_asic_name, - (IS_PIC_PART_REV_A(pcibr_soft->bs_rev_num)) ? "A" : - (IS_PIC_PART_REV_B(pcibr_soft->bs_rev_num)) ? "B" : - (IS_PIC_PART_REV_C(pcibr_soft->bs_rev_num)) ? "C" : - "unknown", pcibr_soft->bs_rev_num)); - - /* PV854845: Must clear write request buffer to avoid parity errors */ - for (i=0; i < PIC_WR_REQ_BUFSIZE; i++) { - ((pic_t *)bridge)->p_wr_req_lower[i] = 0; - ((pic_t *)bridge)->p_wr_req_upper[i] = 0; - ((pic_t *)bridge)->p_wr_req_parity[i] = 0; - } - - pcibr_soft->bs_nasid = NASID_GET(bridge); - - pcibr_soft->bs_bricktype = iobrick_type_get_nasid(pcibr_soft->bs_nasid); - if (pcibr_soft->bs_bricktype < 0) - printk(KERN_WARNING "%s: bricktype was unknown by L1 (ret val = 0x%x)\n", - pcibr_soft->bs_name, pcibr_soft->bs_bricktype); - - pcibr_soft->bs_moduleid = iomoduleid_get(pcibr_soft->bs_nasid); - - if (pcibr_soft->bs_bricktype > 0) { - switch (pcibr_soft->bs_bricktype) { - case MODULE_PXBRICK: - case MODULE_IXBRICK: - case MODULE_OPUSBRICK: - pcibr_soft->bs_first_slot = 0; - pcibr_soft->bs_last_slot = 1; - pcibr_soft->bs_last_reset = 1; - - /* Bus 1 of IXBrick has a IO9, so there are 4 devices, not 2 */ - if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) - && isIO9(pcibr_soft->bs_nasid)) { - pcibr_soft->bs_last_slot = 3; - pcibr_soft->bs_last_reset = 3; - } - break; - - case MODULE_CGBRICK: - pcibr_soft->bs_first_slot = 0; - pcibr_soft->bs_last_slot = 0; - pcibr_soft->bs_last_reset = 0; - break; - - default: - printk(KERN_WARNING "%s: Unknown bricktype: 0x%x\n", - pcibr_soft->bs_name, pcibr_soft->bs_bricktype); - break; - } - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, pcibr_vhdl, - "pic_attach2: bricktype=%d, brickbus=%d, " - "slots %d-%d\n", pcibr_soft->bs_bricktype, - pcibr_widget_to_bus(pcibr_vhdl), - pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot)); - } - - /* - * Initialize bridge and bus locks - */ - spin_lock_init(&pcibr_soft->bs_lock); - - /* - * If we have one, process the hints structure. - */ - if (pcibr_hints) { - unsigned rrb_fixed; - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_HINTS, pcibr_vhdl, - "pic_attach2: pcibr_hints=0x%lx\n", pcibr_hints)); - - rrb_fixed = pcibr_hints->ph_rrb_fixed; - - pcibr_soft->bs_rrb_fixed = rrb_fixed; - - if (pcibr_hints->ph_intr_bits) - pcibr_soft->bs_intr_bits = pcibr_hints->ph_intr_bits; - - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - int hslot = pcibr_hints->ph_host_slot[slot] - 1; - - if (hslot < 0) { - pcibr_soft->bs_slot[slot].host_slot = slot; - } else { - pcibr_soft->bs_slot[slot].has_host = 1; - pcibr_soft->bs_slot[slot].host_slot = hslot; - } - } - } - - /* - * Set-up initial values for state fields - */ - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - pcibr_soft->bs_slot[slot].bss_devio.bssd_space = PCIIO_SPACE_NONE; - pcibr_soft->bs_slot[slot].bss_devio.bssd_ref_cnt = 0; - pcibr_soft->bs_slot[slot].bss_d64_base = PCIBR_D64_BASE_UNSET; - pcibr_soft->bs_slot[slot].bss_d32_base = PCIBR_D32_BASE_UNSET; - pcibr_soft->bs_rrb_valid_dflt[slot][VCHAN0] = -1; - } - - for (ibit = 0; ibit < 8; ++ibit) { - pcibr_soft->bs_intr[ibit].bsi_xtalk_intr = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_soft = pcibr_soft; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_list = NULL; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_ibit = ibit; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_hdlrcnt = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_shared = 0; - pcibr_soft->bs_intr[ibit].bsi_pcibr_intr_wrap.iw_connected = 0; - } - - - /* - * connect up our error handler. PIC has 2 busses (thus resulting in 2 - * pcibr_soft structs under 1 widget), so only register a xwidget error - * handler for PIC's bus0. NOTE: for PIC pcibr_error_handler_wrapper() - * is a wrapper routine we register that will call the real error handler - * pcibr_error_handler() with the correct pcibr_soft struct. - */ - if (busnum == 0) { - xwidget_error_register(xconn_vhdl, - pcibr_error_handler_wrapper, pcibr_soft); - } - - /* - * Clear all pending interrupts. Assume all interrupts are from slot 3 - * until otherise setup. - */ - pcireg_intr_reset_set(pcibr_soft, PIC_IRR_ALL_CLR); - pcireg_intr_device_set(pcibr_soft, 0x006db6db); - - /* Setup the mapping register used for direct mapping */ - pcibr_directmap_init(pcibr_soft); - - /* - * Initialize the PICs control register. - */ - pic_ctrl_reg = pcireg_control_get(pcibr_soft); - - /* Bridges Requester ID: bus = busnum, dev = 0, func = 0 */ - pic_ctrl_reg &= ~PIC_CTRL_BUS_NUM_MASK; - pic_ctrl_reg |= PIC_CTRL_BUS_NUM(busnum); - pic_ctrl_reg &= ~PIC_CTRL_DEV_NUM_MASK; - pic_ctrl_reg &= ~PIC_CTRL_FUN_NUM_MASK; - - pic_ctrl_reg &= ~PIC_CTRL_NO_SNOOP; - pic_ctrl_reg &= ~PIC_CTRL_RELAX_ORDER; - - /* enable parity checking on PICs internal RAM */ - pic_ctrl_reg |= PIC_CTRL_PAR_EN_RESP; - pic_ctrl_reg |= PIC_CTRL_PAR_EN_ATE; - - /* PIC BRINGUP WAR (PV# 862253): dont enable write request parity */ - if (!PCIBR_WAR_ENABLED(PV862253, pcibr_soft)) { - pic_ctrl_reg |= PIC_CTRL_PAR_EN_REQ; - } - - pic_ctrl_reg |= PIC_CTRL_PAGE_SIZE; - - pcireg_control_set(pcibr_soft, pic_ctrl_reg); - - /* Initialize internal mapping entries (ie. the ATEs) */ - for (entry = 0; entry < pcibr_soft->bs_int_ate_size; entry++) - pcireg_int_ate_set(pcibr_soft, entry, 0); - - pcibr_soft->bs_int_ate_resource.start = 0; - pcibr_soft->bs_int_ate_resource.end = pcibr_soft->bs_int_ate_size - 1; - - /* Setup the PICs error interrupt handler. */ - xtalk_intr = xtalk_intr_alloc(xconn_vhdl, (device_desc_t)0, pcibr_vhdl); - - ASSERT(xtalk_intr != NULL); - - irq = ((hub_intr_t)xtalk_intr)->i_bit; - cpu = ((hub_intr_t)xtalk_intr)->i_cpuid; - - intr_unreserve_level(cpu, irq); - ((hub_intr_t)xtalk_intr)->i_bit = SGI_PCIBR_ERROR; - xtalk_intr->xi_vector = SGI_PCIBR_ERROR; - - pcibr_soft->bsi_err_intr = xtalk_intr; - - /* - * On IP35 with XBridge, we do some extra checks in pcibr_setwidint - * in order to work around some addressing limitations. In order - * for that fire wall to work properly, we need to make sure we - * start from a known clean state. - */ - pcibr_clearwidint(pcibr_soft); - - xtalk_intr_connect(xtalk_intr, - (intr_func_t) pcibr_error_intr_handler, - (intr_arg_t) pcibr_soft, - (xtalk_intr_setfunc_t) pcibr_setwidint, - (void *) pcibr_soft); - - request_irq(SGI_PCIBR_ERROR, (void *)pcibr_error_intr_handler, SA_SHIRQ, - "PCIBR error", (intr_arg_t) pcibr_soft); - - PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ALLOC, pcibr_vhdl, - "pcibr_setwidint: target_id=0x%lx, int_addr=0x%lx\n", - pcireg_intr_dst_target_id_get(pcibr_soft), - pcireg_intr_dst_addr_get(pcibr_soft))); - - /* now we can start handling error interrupts */ - int_enable = pcireg_intr_enable_get(pcibr_soft); - int_enable |= PIC_ISR_ERRORS; - - /* PIC BRINGUP WAR (PV# 856864 & 856865): allow the tnums that are - * locked out to be freed up sooner (by timing out) so that the - * read tnums are never completely used up. - */ - if (PCIBR_WAR_ENABLED(PV856864, pcibr_soft)) { - int_enable &= ~PIC_ISR_PCIX_REQ_TOUT; - int_enable &= ~PIC_ISR_XREAD_REQ_TIMEOUT; - - pcireg_req_timeout_set(pcibr_soft, 0x750); - } - - pcireg_intr_enable_set(pcibr_soft, int_enable); - pcireg_intr_mode_set(pcibr_soft, 0); /* dont send 'clear interrupt' pkts */ - pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ - - /* - * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478): Don't use - * RRB0, RRB8, RRB1, and RRB9. Assign them to DEVICE[2|3]--VCHAN3 - * so they are not used. This works since there is currently no - * API to penable VCHAN3. - */ - if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft)) { - pcireg_rrb_bit_set(pcibr_soft, 0, 0x000f000f); /* even rrb reg */ - pcireg_rrb_bit_set(pcibr_soft, 1, 0x000f000f); /* odd rrb reg */ - } - - /* PIC only supports 64-bit direct mapping in PCI-X mode. Since - * all PCI-X devices that initiate memory transactions must be - * capable of generating 64-bit addressed, we force 64-bit DMAs. - */ - pcibr_soft->bs_dma_flags = 0; - if (IS_PCIX(pcibr_soft)) { - pcibr_soft->bs_dma_flags |= PCIIO_DMA_A64; - } - - { - - iopaddr_t prom_base_addr = pcibr_soft->bs_xid << 24; - int prom_base_size = 0x1000000; - int status; - struct resource *res; - - /* Allocate resource maps based on bus page size; for I/O and memory - * space, free all pages except those in the base area and in the - * range set by the PROM. - * - * PROM creates BAR addresses in this format: 0x0ws00000 where w is - * the widget number and s is the device register offset for the slot. - */ - - /* Setup the Bus's PCI IO Root Resource. */ - pcibr_soft->bs_io_win_root_resource.start = PCIBR_BUS_IO_BASE; - pcibr_soft->bs_io_win_root_resource.end = 0xffffffff; - res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); - if (!res) - panic("PCIBR:Unable to allocate resource structure\n"); - - /* Block off the range used by PROM. */ - res->start = prom_base_addr; - res->end = prom_base_addr + (prom_base_size - 1); - status = request_resource(&pcibr_soft->bs_io_win_root_resource, res); - if (status) - panic("PCIBR:Unable to request_resource()\n"); - - /* Setup the Small Window Root Resource */ - pcibr_soft->bs_swin_root_resource.start = PAGE_SIZE; - pcibr_soft->bs_swin_root_resource.end = 0x000FFFFF; - - /* Setup the Bus's PCI Memory Root Resource */ - pcibr_soft->bs_mem_win_root_resource.start = 0x200000; - pcibr_soft->bs_mem_win_root_resource.end = 0xffffffff; - res = (struct resource *) kmalloc( sizeof(struct resource), GFP_KERNEL); - if (!res) - panic("PCIBR:Unable to allocate resource structure\n"); - - /* Block off the range used by PROM. */ - res->start = prom_base_addr; - res->end = prom_base_addr + (prom_base_size - 1); - status = request_resource(&pcibr_soft->bs_mem_win_root_resource, res); - if (status) - panic("PCIBR:Unable to request_resource()\n"); - - } - - - /* build "no-slot" connection point */ - pcibr_info = pcibr_device_info_new(pcibr_soft, PCIIO_SLOT_NONE, - PCIIO_FUNC_NONE, PCIIO_VENDOR_ID_NONE, PCIIO_DEVICE_ID_NONE); - noslot_conn = pciio_device_info_register(pcibr_vhdl, &pcibr_info->f_c); - - /* Store no slot connection point info for tearing it down during detach. */ - pcibr_soft->bs_noslot_conn = noslot_conn; - pcibr_soft->bs_noslot_info = pcibr_info; - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Find out what is out there */ - (void)pcibr_slot_info_init(pcibr_vhdl, slot); - } - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Set up the address space for this slot in the PCI land */ - (void)pcibr_slot_addr_space_init(pcibr_vhdl, slot); - } - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Setup the device register */ - (void)pcibr_slot_device_init(pcibr_vhdl, slot); - } - - if (IS_PCIX(pcibr_soft)) { - pcibr_soft->bs_pcix_rbar_inuse = 0; - pcibr_soft->bs_pcix_rbar_avail = NUM_RBAR; - pcibr_soft->bs_pcix_rbar_percent_allowed = - pcibr_pcix_rbars_calc(pcibr_soft); - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Setup the PCI-X Read Buffer Attribute Registers (RBARs) */ - (void)pcibr_slot_pcix_rbar_init(pcibr_soft, slot); - } - } - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Setup host/guest relations */ - (void)pcibr_slot_guest_info_init(pcibr_vhdl, slot); - } - - /* Handle initial RRB management */ - pcibr_initial_rrb(pcibr_vhdl, - pcibr_soft->bs_first_slot, pcibr_soft->bs_last_slot); - - /* Before any drivers get called that may want to re-allocate RRB's, - * let's get some special cases pre-allocated. Drivers may override - * these pre-allocations, but by doing pre-allocations now we're - * assured not to step all over what the driver intended. - */ - if (pcibr_soft->bs_bricktype > 0) { - switch (pcibr_soft->bs_bricktype) { - case MODULE_PXBRICK: - case MODULE_IXBRICK: - case MODULE_OPUSBRICK: - /* - * If IO9 in bus 1, allocate RRBs to all the IO9 devices - */ - if ((pcibr_widget_to_bus(pcibr_vhdl) == 1) && - (pcibr_soft->bs_slot[0].bss_vendor_id == 0x10A9) && - (pcibr_soft->bs_slot[0].bss_device_id == 0x100A)) { - pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 4); - pcibr_rrb_alloc_init(pcibr_soft, 1, VCHAN0, 4); - pcibr_rrb_alloc_init(pcibr_soft, 2, VCHAN0, 4); - pcibr_rrb_alloc_init(pcibr_soft, 3, VCHAN0, 4); - } else { - pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 4); - pcibr_rrb_alloc_init(pcibr_soft, 1, VCHAN0, 4); - } - break; - - case MODULE_CGBRICK: - pcibr_rrb_alloc_init(pcibr_soft, 0, VCHAN0, 8); - break; - } /* switch */ - } - - - for (slot = pcibr_soft->bs_min_slot; - slot < PCIBR_NUM_SLOTS(pcibr_soft); ++slot) { - /* Call the device attach */ - (void)pcibr_slot_call_device_attach(pcibr_vhdl, slot, 0); - } - - pciio_device_attach(noslot_conn, 0); - - return 0; -} - - -/* - * pci provider functions - * - * mostly in pcibr.c but if any are needed here then - * this might be a way to get them here. - */ -pciio_provider_t pci_pic_provider = -{ - PCIIO_ASIC_TYPE_PIC, - - (pciio_piomap_alloc_f *) pcibr_piomap_alloc, - (pciio_piomap_free_f *) pcibr_piomap_free, - (pciio_piomap_addr_f *) pcibr_piomap_addr, - (pciio_piomap_done_f *) pcibr_piomap_done, - (pciio_piotrans_addr_f *) pcibr_piotrans_addr, - (pciio_piospace_alloc_f *) pcibr_piospace_alloc, - (pciio_piospace_free_f *) pcibr_piospace_free, - - (pciio_dmamap_alloc_f *) pcibr_dmamap_alloc, - (pciio_dmamap_free_f *) pcibr_dmamap_free, - (pciio_dmamap_addr_f *) pcibr_dmamap_addr, - (pciio_dmamap_done_f *) pcibr_dmamap_done, - (pciio_dmatrans_addr_f *) pcibr_dmatrans_addr, - (pciio_dmamap_drain_f *) pcibr_dmamap_drain, - (pciio_dmaaddr_drain_f *) pcibr_dmaaddr_drain, - - (pciio_intr_alloc_f *) pcibr_intr_alloc, - (pciio_intr_free_f *) pcibr_intr_free, - (pciio_intr_connect_f *) pcibr_intr_connect, - (pciio_intr_disconnect_f *) pcibr_intr_disconnect, - (pciio_intr_cpu_get_f *) pcibr_intr_cpu_get, - - (pciio_provider_startup_f *) pcibr_provider_startup, - (pciio_provider_shutdown_f *) pcibr_provider_shutdown, - (pciio_reset_f *) pcibr_reset, - (pciio_endian_set_f *) pcibr_endian_set, - (pciio_config_get_f *) pcibr_config_get, - (pciio_config_set_f *) pcibr_config_set, - - (pciio_error_extract_f *) pcibr_error_extract, - - (pciio_driver_reg_callback_f *) pcibr_driver_reg_callback, - (pciio_driver_unreg_callback_f *) pcibr_driver_unreg_callback, - (pciio_device_unregister_f *) pcibr_device_unregister, -}; diff --git a/arch/ia64/sn/io/sn2/shub.c b/arch/ia64/sn/io/sn2/shub.c deleted file mode 100644 index d5b5b0268..000000000 --- a/arch/ia64/sn/io/sn2/shub.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SHUB_NUM_ECF_REGISTERS 8 - -static uint32_t shub_perf_counts[SHUB_NUM_ECF_REGISTERS]; - -static shubreg_t shub_perf_counts_regs[SHUB_NUM_ECF_REGISTERS] = { - SH_PERFORMANCE_COUNTER0, - SH_PERFORMANCE_COUNTER1, - SH_PERFORMANCE_COUNTER2, - SH_PERFORMANCE_COUNTER3, - SH_PERFORMANCE_COUNTER4, - SH_PERFORMANCE_COUNTER5, - SH_PERFORMANCE_COUNTER6, - SH_PERFORMANCE_COUNTER7 -}; - -static inline void -shub_mmr_write(cnodeid_t cnode, shubreg_t reg, uint64_t val) -{ - int nasid = cnodeid_to_nasid(cnode); - volatile uint64_t *addr = (uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); - - *addr = val; - __ia64_mf_a(); -} - -static inline void -shub_mmr_write_iospace(cnodeid_t cnode, shubreg_t reg, uint64_t val) -{ - int nasid = cnodeid_to_nasid(cnode); - - REMOTE_HUB_S(nasid, reg, val); -} - -static inline void -shub_mmr_write32(cnodeid_t cnode, shubreg_t reg, uint32_t val) -{ - int nasid = cnodeid_to_nasid(cnode); - volatile uint32_t *addr = (uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); - - *addr = val; - __ia64_mf_a(); -} - -static inline uint64_t -shub_mmr_read(cnodeid_t cnode, shubreg_t reg) -{ - int nasid = cnodeid_to_nasid(cnode); - volatile uint64_t val; - - val = *(uint64_t *)(GLOBAL_MMR_ADDR(nasid, reg)); - __ia64_mf_a(); - - return val; -} - -static inline uint64_t -shub_mmr_read_iospace(cnodeid_t cnode, shubreg_t reg) -{ - int nasid = cnodeid_to_nasid(cnode); - - return REMOTE_HUB_L(nasid, reg); -} - -static inline uint32_t -shub_mmr_read32(cnodeid_t cnode, shubreg_t reg) -{ - int nasid = cnodeid_to_nasid(cnode); - volatile uint32_t val; - - val = *(uint32_t *)(GLOBAL_MMR_ADDR(nasid, reg)); - __ia64_mf_a(); - - return val; -} - -static int -reset_shub_stats(cnodeid_t cnode) -{ - int i; - - for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { - shub_perf_counts[i] = 0; - shub_mmr_write32(cnode, shub_perf_counts_regs[i], 0); - } - return 0; -} - -static int -configure_shub_stats(cnodeid_t cnode, unsigned long arg) -{ - uint64_t *p = (uint64_t *)arg; - uint64_t i; - uint64_t regcnt; - uint64_t regval[2]; - - if (copy_from_user((void *)®cnt, p, sizeof(regcnt))) - return -EFAULT; - - for (p++, i=0; i < regcnt; i++, p += 2) { - if (copy_from_user((void *)regval, (void *)p, sizeof(regval))) - return -EFAULT; - if (regval[0] & 0x7) { - printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]); - return -EINVAL; - } - shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]); - } - return 0; -} - -static int -capture_shub_stats(cnodeid_t cnode, uint32_t *counts) -{ - int i; - - for (i=0; i < SHUB_NUM_ECF_REGISTERS; i++) { - counts[i] = shub_mmr_read32(cnode, shub_perf_counts_regs[i]); - } - return 0; -} - -static int -shubstats_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - cnodeid_t cnode; - uint64_t longarg; - uint64_t intarg; - uint64_t regval[2]; - int nasid; - - cnode = (cnodeid_t)(u64)file->f_dentry->d_fsdata; - if (cnode < 0 || cnode >= numnodes) - return -ENODEV; - - switch (cmd) { - case SNDRV_SHUB_CONFIGURE: - return configure_shub_stats(cnode, arg); - break; - - case SNDRV_SHUB_RESETSTATS: - reset_shub_stats(cnode); - break; - - case SNDRV_SHUB_INFOSIZE: - longarg = sizeof(shub_perf_counts); - if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) { - return -EFAULT; - } - break; - - case SNDRV_SHUB_GETSTATS: - capture_shub_stats(cnode, shub_perf_counts); - if (copy_to_user((void *)arg, shub_perf_counts, - sizeof(shub_perf_counts))) { - return -EFAULT; - } - break; - - case SNDRV_SHUB_GETNASID: - nasid = cnodeid_to_nasid(cnode); - if (copy_to_user((void *)arg, &nasid, - sizeof(nasid))) { - return -EFAULT; - } - break; - - case SNDRV_SHUB_GETMMR32: - intarg = shub_mmr_read32(cnode, arg); - if (copy_to_user((void *)arg, &intarg, - sizeof(intarg))) { - return -EFAULT; - } - break; - - case SNDRV_SHUB_GETMMR64: - case SNDRV_SHUB_GETMMR64_IO: - if (cmd == SNDRV_SHUB_GETMMR64) - longarg = shub_mmr_read(cnode, arg); - else - longarg = shub_mmr_read_iospace(cnode, arg); - if (copy_to_user((void *)arg, &longarg, sizeof(longarg))) - return -EFAULT; - break; - - case SNDRV_SHUB_PUTMMR64: - case SNDRV_SHUB_PUTMMR64_IO: - if (copy_from_user((void *)regval, (void *)arg, sizeof(regval))) - return -EFAULT; - if (regval[0] & 0x7) { - printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]); - return -EINVAL; - } - if (cmd == SNDRV_SHUB_PUTMMR64) - shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]); - else - shub_mmr_write_iospace(cnode, (shubreg_t)regval[0], regval[1]); - break; - - default: - return -EINVAL; - } - - return 0; -} - -struct file_operations shub_mon_fops = { - .ioctl = shubstats_ioctl, -}; diff --git a/arch/ia64/sn/io/sn2/shub_intr.c b/arch/ia64/sn/io/sn2/shub_intr.c deleted file mode 100644 index a0a42bdf0..000000000 --- a/arch/ia64/sn/io/sn2/shub_intr.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All Rights Reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* ARGSUSED */ -void -hub_intr_init(vertex_hdl_t hubv) -{ -} - -xwidgetnum_t -hub_widget_id(nasid_t nasid) -{ - - if (!(nasid & 1)) { - hubii_wcr_t ii_wcr; /* the control status register */ - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid,IIO_WCR); - return ii_wcr.wcr_fields_s.wcr_widget_id; - } else { - /* ICE does not have widget id. */ - return(-1); - } -} - -static hub_intr_t -do_hub_intr_alloc(vertex_hdl_t dev, - device_desc_t dev_desc, - vertex_hdl_t owner_dev, - int uncond_nothread) -{ - cpuid_t cpu; - int vector; - hub_intr_t intr_hdl; - cnodeid_t cnode; - int cpuphys, slice; - int nasid; - iopaddr_t xtalk_addr; - struct xtalk_intr_s *xtalk_info; - xwidget_info_t xwidget_info; - - cpu = intr_heuristic(dev, -1, &vector); - if (cpu == CPU_NONE) { - printk("Unable to allocate interrupt for 0x%p\n", (void *)owner_dev); - return(0); - } - - cpuphys = cpu_physical_id(cpu); - slice = cpu_physical_id_to_slice(cpuphys); - nasid = cpu_physical_id_to_nasid(cpuphys); - cnode = cpuid_to_cnodeid(cpu); - - if (slice) { - xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47); - } else { - xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47); - } - - intr_hdl = kmalloc(sizeof(struct hub_intr_s), GFP_KERNEL); - ASSERT_ALWAYS(intr_hdl); - memset(intr_hdl, 0, sizeof(struct hub_intr_s)); - - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = dev; - xtalk_info->xi_vector = vector; - xtalk_info->xi_addr = xtalk_addr; - - xwidget_info = xwidget_info_get(dev); - if (xwidget_info) { - xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info); - } - - intr_hdl->i_cpuid = cpu; - intr_hdl->i_bit = vector; - intr_hdl->i_flags |= HUB_INTR_IS_ALLOCED; - - return intr_hdl; -} - -hub_intr_t -hub_intr_alloc(vertex_hdl_t dev, - device_desc_t dev_desc, - vertex_hdl_t owner_dev) -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0)); -} - -hub_intr_t -hub_intr_alloc_nothd(vertex_hdl_t dev, - device_desc_t dev_desc, - vertex_hdl_t owner_dev) -{ - return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1)); -} - -void -hub_intr_free(hub_intr_t intr_hdl) -{ - cpuid_t cpu = intr_hdl->i_cpuid; - int vector = intr_hdl->i_bit; - xtalk_intr_t xtalk_info; - - if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) { - xtalk_info = &intr_hdl->i_xtalk_info; - xtalk_info->xi_dev = 0; - xtalk_info->xi_vector = 0; - xtalk_info->xi_addr = 0; - hub_intr_disconnect(intr_hdl); - } - - if (intr_hdl->i_flags & HUB_INTR_IS_ALLOCED) { - kfree(intr_hdl); - } - intr_unreserve_level(cpu, vector); -} - -int -hub_intr_connect(hub_intr_t intr_hdl, - intr_func_t intr_func, /* xtalk intr handler */ - void *intr_arg, /* arg to intr handler */ - xtalk_intr_setfunc_t setfunc, - void *setfunc_arg) -{ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int vector = intr_hdl->i_bit; - - ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED); - - rv = intr_connect_level(cpu, vector); - if (rv < 0) - return rv; - - intr_hdl->i_xtalk_info.xi_setfunc = setfunc; - intr_hdl->i_xtalk_info.xi_sfarg = setfunc_arg; - - if (setfunc) { - (*setfunc)((xtalk_intr_t)intr_hdl); - } - - intr_hdl->i_flags |= HUB_INTR_IS_CONNECTED; - - return 0; -} - -/* - * Disassociate handler with the specified interrupt. - */ -void -hub_intr_disconnect(hub_intr_t intr_hdl) -{ - /*REFERENCED*/ - int rv; - cpuid_t cpu = intr_hdl->i_cpuid; - int bit = intr_hdl->i_bit; - xtalk_intr_setfunc_t setfunc; - - setfunc = intr_hdl->i_xtalk_info.xi_setfunc; - - /* TBD: send disconnected interrupts somewhere harmless */ - if (setfunc) (*setfunc)((xtalk_intr_t)intr_hdl); - - rv = intr_disconnect_level(cpu, bit); - ASSERT(rv == 0); - intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED; -} - -/* - * Redirect an interrupt to another cpu. - */ - -void -sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu) -{ - unsigned long bit; - int cpuphys, slice; - nasid_t nasid; - unsigned long xtalk_addr; - int irq; - int i; - int old_cpu; - int new_cpu; - - cpuphys = cpu_physical_id(cpu); - slice = cpu_physical_id_to_slice(cpuphys); - nasid = cpu_physical_id_to_nasid(cpuphys); - - for (i = CPUS_PER_NODE - 1; i >= 0; i--) { - new_cpu = nasid_slice_to_cpuid(nasid, i); - if (new_cpu == NR_CPUS) { - continue; - } - - if (!cpu_online(new_cpu)) { - continue; - } - break; - } - - if (enable_shub_wars_1_1() && slice != i) { - printk("smp_affinity WARNING: SHUB 1.1 present: cannot target cpu %d, targeting cpu %d instead.\n",(int)cpu, new_cpu); - cpu = new_cpu; - slice = i; - } - - if (slice) { - xtalk_addr = SH_II_INT1 | ((unsigned long)nasid << 36) | (1UL << 47); - } else { - xtalk_addr = SH_II_INT0 | ((unsigned long)nasid << 36) | (1UL << 47); - } - - for (bit = 0; bit < 8; bit++) { - if (intr->bi_ibits & (1 << bit) ) { - /* Disable interrupts. */ - pcireg_intr_enable_bit_clr(intr->bi_soft, bit); - /* Reset Host address (Interrupt destination) */ - pcireg_intr_addr_addr_set(intr->bi_soft, bit, xtalk_addr); - /* Enable interrupt */ - pcireg_intr_enable_bit_set(intr->bi_soft, bit); - /* Force an interrupt, just in case. */ - pcireg_force_intr_set(intr->bi_soft, bit); - } - } - irq = intr->bi_irq; - old_cpu = intr->bi_cpu; - if (pdacpu(cpu)->sn_first_irq == 0 || pdacpu(cpu)->sn_first_irq > irq) { - pdacpu(cpu)->sn_first_irq = irq; - } - if (pdacpu(cpu)->sn_last_irq < irq) { - pdacpu(cpu)->sn_last_irq = irq; - } - pdacpu(old_cpu)->sn_num_irqs--; - pdacpu(cpu)->sn_num_irqs++; - intr->bi_cpu = (int)cpu; -} diff --git a/arch/ia64/sn/io/sn2/shuberror.c b/arch/ia64/sn/io/sn2/shuberror.c deleted file mode 100644 index e2a991cca..000000000 --- a/arch/ia64/sn/io/sn2/shuberror.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern void hubni_eint_init(cnodeid_t cnode); -extern void hubii_eint_init(cnodeid_t cnode); -extern irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep); -int hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); -int hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo); -extern void bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop); -void print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, - ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, - ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe); - -extern int maxcpus; -extern error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); - -#define HUB_ERROR_PERIOD (120 * HZ) /* 2 minutes */ - -void -hub_error_clear(nasid_t nasid) -{ - int i; - - /* - * Make sure spurious write response errors are cleared - * (values are from hub_set_prb()) - */ - for (i = 0; i <= HUB_WIDGET_ID_MAX - HUB_WIDGET_ID_MIN + 1; i++) { - iprb_t prb; - - prb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t))); - - /* Clear out some fields */ - prb.iprb_ovflow = 1; - prb.iprb_bnakctr = 0; - prb.iprb_anakctr = 0; - - prb.iprb_xtalkctr = 3; /* approx. PIO credits for the widget */ - - REMOTE_HUB_S(nasid, IIO_IOPRB_0 + (i * sizeof(hubreg_t)), prb.iprb_regval); - } - - REMOTE_HUB_S(nasid, IIO_IECLR, -1); - -} - - -/* - * Function : hub_error_init - * Purpose : initialize the error handling requirements for a given hub. - * Parameters : cnode, the compact nodeid. - * Assumptions : Called only once per hub, either by a local cpu. Or by a - * remote cpu, when this hub is headless.(cpuless) - * Returns : None - */ - -void -hub_error_init(cnodeid_t cnode) -{ - nasid_t nasid; - - nasid = cnodeid_to_nasid(cnode); - hub_error_clear(nasid); - - - /* - * Now setup the hub ii error interrupt handler. - */ - - hubii_eint_init(cnode); - - return; -} - -/* - * Function : hubii_eint_init - * Parameters : cnode - * Purpose : to initialize the hub iio error interrupt. - * Assumptions : Called once per hub, by the cpu which will ultimately - * handle this interrupt. - * Returns : None. - */ - -void -hubii_eint_init(cnodeid_t cnode) -{ - int bit, rv; - ii_iidsr_u_t hubio_eint; - hubinfo_t hinfo; - cpuid_t intr_cpu; - vertex_hdl_t hub_v; - int bit_pos_to_irq(int bit); - ii_ilcsr_u_t ilcsr; - - - hub_v = (vertex_hdl_t)cnodeid_to_vertex(cnode); - ASSERT_ALWAYS(hub_v); - hubinfo_get(hub_v, &hinfo); - - ASSERT(hinfo); - ASSERT(hinfo->h_cnodeid == cnode); - - ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); - if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { - /* - * HUB II link is not up. Disable LLP. Clear old errors. - * Enable interrupts to handle BTE errors. - */ - ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); - } - - /* Select a possible interrupt target where there is a free interrupt - * bit and also reserve the interrupt bit for this IO error interrupt - */ - intr_cpu = intr_heuristic(hub_v, SGI_II_ERROR, &bit); - if (intr_cpu == CPU_NONE) { - printk("hubii_eint_init: intr_heuristic failed, cnode %d", cnode); - return; - } - - rv = intr_connect_level(intr_cpu, SGI_II_ERROR); - request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); - irq_descp(bit)->status |= SN2_IRQ_PER_HUB; - ASSERT_ALWAYS(rv >= 0); - hubio_eint.ii_iidsr_regval = 0; - hubio_eint.ii_iidsr_fld_s.i_enable = 1; - hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ - hubio_eint.ii_iidsr_fld_s.i_node = cnodeid_to_nasid(cnode); - hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); - -} - - -/*ARGSUSED*/ -irqreturn_t -hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) -{ - vertex_hdl_t hub_v; - hubinfo_t hinfo; - ii_wstat_u_t wstat; - hubreg_t idsr; - - - /* two levels of casting avoids compiler warning.!! */ - hub_v = (vertex_hdl_t)(long)(arg); - ASSERT(hub_v); - - hubinfo_get(hub_v, &hinfo); - - idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); -#if 0 - if (idsr & 0x1) { - /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ - printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); - printk("***** Please file PV with the above messages *****\n"); - /* panic("We have to panic to prevent further unknown states ..\n"); */ - } -#endif - - /* - * Identify the reason for error. - */ - wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); - - if (wstat.ii_wstat_fld_s.w_crazy) { - char *reason; - /* - * We can do a couple of things here. - * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check - * which of these caused the CRAZY bit to be set. - * You may be able to check if the Link is up really. - */ - if (wstat.ii_wstat_fld_s.w_tx_mx_rty) - reason = "Micro Packet Retry Timeout"; - else if (wstat.ii_wstat_fld_s.w_xt_tail_to) - reason = "Crosstalk Tail Timeout"; - else if (wstat.ii_wstat_fld_s.w_xt_crd_to) - reason = "Crosstalk Credit Timeout"; - else { - hubreg_t hubii_imem; - /* - * Check if widget 0 has been marked as shutdown, or - * if BTE 0/1 has been marked. - */ - hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); - if (hubii_imem & IIO_IMEM_W0ESD) - reason = "Hub Widget 0 has been Shutdown"; - else if (hubii_imem & IIO_IMEM_B0ESD) - reason = "BTE 0 has been shutdown"; - else if (hubii_imem & IIO_IMEM_B1ESD) - reason = "BTE 1 has been shutdown"; - else reason = "Unknown"; - - } - /* - * Only print the II_ECRAZY message if there is an attached xbow. - */ - if (NODEPDA(hinfo->h_cnodeid)->xbow_vhdl != 0) { - printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", - hinfo->h_nasid, hinfo->h_cnodeid, reason); - } - } - - - /* - * Before processing any interrupt related information, clear all - * error indication and reenable interrupts. This will prevent - * lost interrupts due to the interrupt handler scanning past a PRB/CRB - * which has not errorred yet and then the PRB/CRB goes into error. - * Note, PRB errors are cleared individually. - */ - REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xff0000); - idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; - REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); - - - /* - * It's a toss as to which one among PRB/CRB to check first. - * Current decision is based on the severity of the errors. - * IO CRB errors tend to be more severe than PRB errors. - * - * It is possible for BTE errors to have been handled already, so we - * may not see any errors handled here. - */ - (void)hubiio_crb_error_handler(hub_v, hinfo); - (void)hubiio_prb_error_handler(hub_v, hinfo); - - return IRQ_HANDLED; -} - -/* - * Free the hub CRB "crbnum" which encountered an error. - * Assumption is, error handling was successfully done, - * and we now want to return the CRB back to Hub for normal usage. - * - * In order to free the CRB, all that's needed is to de-allocate it - * - * Assumption: - * No other processor is mucking around with the hub control register. - * So, upper layer has to single thread this. - */ -void -hubiio_crb_free(hubinfo_t hinfo, int crbnum) -{ - ii_icrb0_b_u_t icrbb; - - /* - * The hardware does NOT clear the mark bit, so it must get cleared - * here to be sure the error is not processed twice. - */ - icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICRB_B(crbnum)); - icrbb.b_mark = 0; - REMOTE_HUB_S(hinfo->h_nasid, IIO_ICRB_B(crbnum), icrbb.ii_icrb0_b_regval); - - /* - * Deallocate the register. - */ - - REMOTE_HUB_S(hinfo->h_nasid, IIO_ICDR, (IIO_ICDR_PND | crbnum)); - - /* - * Wait till hub indicates it's done. - */ - while (REMOTE_HUB_L(hinfo->h_nasid, IIO_ICDR) & IIO_ICDR_PND) - udelay(1); - -} - - -/* - * Array of error names that get logged in CRBs - */ -char *hubiio_crb_errors[] = { - "Directory Error", - "CRB Poison Error", - "I/O Write Error", - "I/O Access Error", - "I/O Partial Write Error", - "I/O Partial Read Error", - "I/O Timeout Error", - "Xtalk Error Packet" -}; - -void -print_crb_fields(int crb_num, ii_icrb0_a_u_t icrba, - ii_icrb0_b_u_t icrbb, ii_icrb0_c_u_t icrbc, - ii_icrb0_d_u_t icrbd, ii_icrb0_e_u_t icrbe) -{ - printk("CRB %d regA\n\t" - "a_iow 0x%x\n\t" - "valid0x%x\n\t" - "Address0x%lx\n\t" - "a_tnum 0x%x\n\t" - "a_sidn 0x%x\n", - crb_num, - icrba.a_iow, - icrba.a_valid, - icrba.a_addr, - icrba.a_tnum, - icrba.a_sidn); - printk("CRB %d regB\n\t" - "b_imsgtype 0x%x\n\t" - "b_imsg 0x%x\n" - "\tb_use_old 0x%x\n\t" - "b_initiator 0x%x\n\t" - "b_exc 0x%x\n" - "\tb_ackcnt 0x%x\n\t" - "b_resp 0x%x\n\t" - "b_ack 0x%x\n" - "\tb_hold 0x%x\n\t" - "b_wb 0x%x\n\t" - "b_intvn 0x%x\n" - "\tb_stall_ib 0x%x\n\t" - "b_stall_int 0x%x\n" - "\tb_stall_bte_0 0x%x\n\t" - "b_stall_bte_1 0x%x\n" - "\tb_error 0x%x\n\t" - "b_lnetuce 0x%x\n\t" - "b_mark 0x%x\n\t" - "b_xerr 0x%x\n", - crb_num, - icrbb.b_imsgtype, - icrbb.b_imsg, - icrbb.b_use_old, - icrbb.b_initiator, - icrbb.b_exc, - icrbb.b_ackcnt, - icrbb.b_resp, - icrbb.b_ack, - icrbb.b_hold, - icrbb.b_wb, - icrbb.b_intvn, - icrbb.b_stall_ib, - icrbb.b_stall_int, - icrbb.b_stall_bte_0, - icrbb.b_stall_bte_1, - icrbb.b_error, - icrbb.b_lnetuce, - icrbb.b_mark, - icrbb.b_xerr); - printk("CRB %d regC\n\t" - "c_source 0x%x\n\t" - "c_xtsize 0x%x\n\t" - "c_cohtrans 0x%x\n\t" - "c_btenum 0x%x\n\t" - "c_gbr 0x%x\n\t" - "c_doresp 0x%x\n\t" - "c_barrop 0x%x\n\t" - "c_suppl 0x%x\n", - crb_num, - icrbc.c_source, - icrbc.c_xtsize, - icrbc.c_cohtrans, - icrbc.c_btenum, - icrbc.c_gbr, - icrbc.c_doresp, - icrbc.c_barrop, - icrbc.c_suppl); - printk("CRB %d regD\n\t" - "d_bteaddr 0x%lx\n\t" - "d_bteop 0x%x\n\t" - "d_pripsc 0x%x\n\t" - "d_pricnt 0x%x\n\t" - "d_sleep 0x%x\n\t", - crb_num, - icrbd.d_bteaddr, - icrbd.d_bteop, - icrbd.d_pripsc, - icrbd.d_pricnt, - icrbd.d_sleep); - printk("CRB %d regE\n\t" - "icrbe_timeout 0x%x\n\t" - "icrbe_context 0x%x\n\t" - "icrbe_toutvld 0x%x\n\t" - "icrbe_ctxtvld 0x%x\n\t", - crb_num, - icrbe.icrbe_timeout, - icrbe.icrbe_context, - icrbe.icrbe_toutvld, - icrbe.icrbe_ctxtvld); -} - -/* - * hubiio_crb_error_handler - * - * This routine gets invoked when a hub gets an error - * interrupt. So, the routine is running in interrupt context - * at error interrupt level. - * Action: - * It's responsible for identifying ALL the CRBs that are marked - * with error, and process them. - * - * If you find the CRB that's marked with error, map this to the - * reason it caused error, and invoke appropriate error handler. - * - * XXX Be aware of the information in the context register. - * - * NOTE: - * Use REMOTE_HUB_* macro instead of LOCAL_HUB_* so that the interrupt - * handler can be run on any node. (not necessarily the node - * corresponding to the hub that encountered error). - */ - -int -hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) -{ - cnodeid_t cnode; - nasid_t nasid; - ii_icrb0_a_u_t icrba; /* II CRB Register A */ - ii_icrb0_b_u_t icrbb; /* II CRB Register B */ - ii_icrb0_c_u_t icrbc; /* II CRB Register C */ - ii_icrb0_d_u_t icrbd; /* II CRB Register D */ - ii_icrb0_e_u_t icrbe; /* II CRB Register D */ - int i; - int num_errors = 0; /* Num of errors handled */ - ioerror_t ioerror; - int rc; - - nasid = hinfo->h_nasid; - cnode = nasid_to_cnodeid(nasid); - - /* - * XXX - Add locking for any recovery actions - */ - /* - * Scan through all CRBs in the Hub, and handle the errors - * in any of the CRBs marked. - */ - for (i = 0; i < IIO_NUM_CRBS; i++) { - /* Check this crb entry to see if it is in error. */ - icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); - - if (icrbb.b_mark == 0) { - continue; - } - - icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); - - IOERROR_INIT(&ioerror); - - /* read other CRB error registers. */ - icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); - icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); - icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); - - IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); - - /* Check if this error is due to BTE operation, - * and handle it separately. - */ - if (icrbd.d_bteop || - ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || - icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && - (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || - icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))){ - - int bte_num; - - if (icrbd.d_bteop) - bte_num = icrbc.c_btenum; - else /* b_initiator bit 2 gives BTE number */ - bte_num = (icrbb.b_initiator & 0x4) >> 2; - - hubiio_crb_free(hinfo, i); - - bte_crb_error_handler(hub_v, bte_num, - i, &ioerror, - icrbd.d_bteop); - num_errors++; - continue; - } - - /* - * XXX - * Assuming the only other error that would reach here is - * crosstalk errors. - * If CRB times out on a message from Xtalk, it changes - * the message type to CRB. - * - * If we get here due to other errors (SN0net/CRB) - * what's the action ? - */ - - /* - * Pick out the useful fields in CRB, and - * tuck them away into ioerror structure. - */ - IOERROR_SETVALUE(&ioerror,xtalkaddr,icrba.a_addr << IIO_ICRB_ADDR_SHFT); - IOERROR_SETVALUE(&ioerror,widgetnum,icrba.a_sidn); - - - if (icrba.a_iow){ - /* - * XXX We shouldn't really have BRIDGE-specific code - * here, but alas.... - * - * The BRIDGE (or XBRIDGE) sets the upper bit of TNUM - * to indicate a WRITE operation. It sets the next - * bit to indicate an INTERRUPT operation. The bottom - * 3 bits of TNUM indicate which device was responsible. - */ - IOERROR_SETVALUE(&ioerror,widgetdev, - TNUM_TO_WIDGET_DEV(icrba.a_tnum)); - /* - * The encoding of TNUM (see comments above) is - * different for PIC. So we'll save TNUM here and - * deal with the differences later when we can - * determine if we're using a Bridge or the PIC. - * - * XXX: We may be able to remove saving the widgetdev - * above and just sort it out of TNUM later. - */ - IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); - - } - if (icrbb.b_error) { - /* - * CRB 'i' has some error. Identify the type of error, - * and try to handle it. - * - */ - switch(icrbb.b_ecode) { - case IIO_ICRB_ECODE_PERR: - case IIO_ICRB_ECODE_WERR: - case IIO_ICRB_ECODE_AERR: - case IIO_ICRB_ECODE_PWERR: - case IIO_ICRB_ECODE_TOUT: - case IIO_ICRB_ECODE_XTERR: - printk("Shub II CRB %d: error %s on hub cnodeid: %d", - i, hubiio_crb_errors[icrbb.b_ecode], cnode); - /* - * Any sort of write error is mostly due - * bad programming (Note it's not a timeout.) - * So, invoke hub_iio_error_handler with - * appropriate information. - */ - IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); - - /* Go through the error bit lookup phase */ - if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); - rc = hub_ioerror_handler( - hub_v, - DMA_WRITE_ERROR, - MODE_DEVERROR, - &ioerror); - if (rc == IOERROR_HANDLED) { - rc = hub_ioerror_handler( - hub_v, - DMA_WRITE_ERROR, - MODE_DEVREENABLE, - &ioerror); - }else { - printk("Unable to handle %s on hub %d", - hubiio_crb_errors[icrbb.b_ecode], - cnode); - /* panic; */ - } - /* Go to Next error */ - print_crb_fields(i, icrba, icrbb, icrbc, - icrbd, icrbe); - hubiio_crb_free(hinfo, i); - continue; - case IIO_ICRB_ECODE_PRERR: - case IIO_ICRB_ECODE_DERR: - printk("Shub II CRB %d: error %s on hub : %d", - i, hubiio_crb_errors[icrbb.b_ecode], cnode); - /* panic */ - default: - printk("Shub II CRB error (code : %d) on hub : %d", - icrbb.b_ecode, cnode); - /* panic */ - } - } - /* - * Error is not indicated via the errcode field - * Check other error indications in this register. - */ - if (icrbb.b_xerr) { - printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", - i, cnode); - /* panic */ - } - if (icrbb.b_lnetuce) { - printk("Shub II CRB %d: Uncorrectable data error detected on data " - " from NUMAlink to node %d", - i, cnode); - /* panic */ - } - print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); - - - - - - if (icrbb.b_error) { - /* - * CRB 'i' has some error. Identify the type of error, - * and try to handle it. - */ - switch(icrbb.b_ecode) { - case IIO_ICRB_ECODE_PERR: - case IIO_ICRB_ECODE_WERR: - case IIO_ICRB_ECODE_AERR: - case IIO_ICRB_ECODE_PWERR: - - printk("%s on hub cnodeid: %d", - hubiio_crb_errors[icrbb.b_ecode], cnode); - /* - * Any sort of write error is mostly due - * bad programming (Note it's not a timeout.) - * So, invoke hub_iio_error_handler with - * appropriate information. - */ - IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); - - rc = hub_ioerror_handler( - hub_v, - DMA_WRITE_ERROR, - MODE_DEVERROR, - &ioerror); - - if (rc == IOERROR_HANDLED) { - rc = hub_ioerror_handler( - hub_v, - DMA_WRITE_ERROR, - MODE_DEVREENABLE, - &ioerror); - ASSERT(rc == IOERROR_HANDLED); - }else { - - panic("Unable to handle %s on hub %d", - hubiio_crb_errors[icrbb.b_ecode], - cnode); - /*NOTREACHED*/ - } - /* Go to Next error */ - hubiio_crb_free(hinfo, i); - continue; - - case IIO_ICRB_ECODE_PRERR: - - case IIO_ICRB_ECODE_TOUT: - case IIO_ICRB_ECODE_XTERR: - - case IIO_ICRB_ECODE_DERR: - panic("Fatal %s on hub : %d", - hubiio_crb_errors[icrbb.b_ecode], cnode); - /*NOTREACHED*/ - - default: - panic("Fatal error (code : %d) on hub : %d", - icrbb.b_ecode, cnode); - /*NOTREACHED*/ - - } - } /* if (icrbb.b_error) */ - - /* - * Error is not indicated via the errcode field - * Check other error indications in this register. - */ - - if (icrbb.b_xerr) { - panic("Xtalk Packet with error bit set to hub %d", - cnode); - /*NOTREACHED*/ - } - - if (icrbb.b_lnetuce) { - panic("Uncorrectable data error detected on data " - " from Craylink to node %d", - cnode); - /*NOTREACHED*/ - } - - } - return num_errors; -} - -/* - * hubii_check_widget_disabled - * - * Check if PIO access to the specified widget is disabled due - * to any II errors that are currently set. - * - * The specific error bits checked are: - * IPRBx register: SPUR_RD (51) - * SPUR_WR (50) - * RD_TO (49) - * ERROR (48) - * - * WSTAT register: CRAZY (32) - */ - -int -hubii_check_widget_disabled(nasid_t nasid, int wnum) -{ - iprb_t iprb; - ii_wstat_u_t wstat; - - iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum)); - if (iprb.iprb_regval & (IIO_PRB_SPUR_RD | IIO_PRB_SPUR_WR | - IIO_PRB_RD_TO | IIO_PRB_ERROR)) { -#ifdef DEBUG - printk(KERN_WARNING "II error, IPRB%x=0x%lx\n", wnum, iprb.iprb_regval); -#endif - return(1); - } - - wstat.ii_wstat_regval = REMOTE_HUB_L(nasid, IIO_WSTAT); - if (wstat.ii_wstat_regval & IIO_WSTAT_ECRAZY) { -#ifdef DEBUG - printk(KERN_WARNING "II error, WSTAT=0x%lx\n", wstat.ii_wstat_regval); -#endif - return(1); - } - return(0); -} - -/*ARGSUSED*/ -/* - * hubii_prb_handler - * Handle the error reported in the PRB for wiget number wnum. - * This typically happens on a PIO write error. - * There is nothing much we can do in this interrupt context for - * PIO write errors. For e.g. QL scsi controller has the - * habit of flaking out on PIO writes. - * Print a message and try to continue for now - * Cleanup involes freeing the PRB register - */ -static void -hubii_prb_handler(vertex_hdl_t hub_v, hubinfo_t hinfo, int wnum) -{ - nasid_t nasid; - - nasid = hinfo->h_nasid; - /* - * Clear error bit by writing to IECLR register. - */ - REMOTE_HUB_S(nasid, IIO_IECLR, (1 << wnum)); - /* - * PIO Write to Widget 'i' got into an error. - * Invoke hubiio_error_handler with this information. - */ - printk( "Hub nasid %d got a PIO Write error from widget %d, " - "cleaning up and continuing", nasid, wnum); - /* - * XXX - * It may be necessary to adjust IO PRB counter - * to account for any lost credits. - */ -} - -int -hubiio_prb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) -{ - int wnum; - nasid_t nasid; - int num_errors = 0; - iprb_t iprb; - - nasid = hinfo->h_nasid; - /* - * Check if IPRB0 has any error first. - */ - iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(0)); - if (iprb.iprb_error) { - num_errors++; - hubii_prb_handler(hub_v, hinfo, 0); - } - /* - * Look through PRBs 8 - F to see if any of them has error bit set. - * If true, invoke hub iio error handler for this widget. - */ - for (wnum = HUB_WIDGET_ID_MIN; wnum <= HUB_WIDGET_ID_MAX; wnum++) { - iprb.iprb_regval = REMOTE_HUB_L(nasid, IIO_IOPRB(wnum)); - - if (!iprb.iprb_error) - continue; - - num_errors++; - hubii_prb_handler(hub_v, hinfo, wnum); - } - - return num_errors; -} - diff --git a/arch/ia64/sn/io/sn2/shubio.c b/arch/ia64/sn/io/sn2/shubio.c deleted file mode 100644 index a4540c1b7..000000000 --- a/arch/ia64/sn/io/sn2/shubio.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * 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. - * - * Copyright (C) 1992 - 1997, 2000,2002-2003 Silicon Graphics, Inc. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -error_state_t error_state_get(vertex_hdl_t v); -error_return_code_t error_state_set(vertex_hdl_t v,error_state_t new_state); - - -/* - * Get the xtalk provider function pointer for the - * specified hub. - */ - -/*ARGSUSED*/ -int -hub_xp_error_handler( - vertex_hdl_t hub_v, - nasid_t nasid, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - /*REFERENCED*/ - hubreg_t iio_imem; - vertex_hdl_t xswitch; - error_state_t e_state; - cnodeid_t cnode; - - /* - * Before walking down to the next level, check if - * the I/O link is up. If it's been disabled by the - * hub ii for some reason, we can't even touch the - * widget registers. - */ - iio_imem = REMOTE_HUB_L(nasid, IIO_IMEM); - - if (!(iio_imem & (IIO_IMEM_B0ESD|IIO_IMEM_W0ESD))){ - /* - * IIO_IMEM_B0ESD getting set, indicates II shutdown - * on HUB0 parts.. Hopefully that's not true for - * Hub1 parts.. - * - * - * If either one of them is shut down, can't - * go any further. - */ - return IOERROR_XTALKLEVEL; - } - - /* Get the error state of the hub */ - e_state = error_state_get(hub_v); - - cnode = nasid_to_cnodeid(nasid); - - xswitch = NODEPDA(cnode)->basew_xc; - - /* Set the error state of the crosstalk device to that of - * hub. - */ - if (error_state_set(xswitch , e_state) == - ERROR_RETURN_CODE_CANNOT_SET_STATE) - return(IOERROR_UNHANDLED); - - /* Clean the error state of the hub if we are in the action handling - * phase. - */ - if (e_state == ERROR_STATE_ACTION) - (void)error_state_set(hub_v, ERROR_STATE_NONE); - /* hand the error off to the switch or the directly - * connected crosstalk device. - */ - return xtalk_error_handler(xswitch, - error_code, mode, ioerror); - -} - -/* - * Check if the widget in error has been enabled for PIO accesses - */ -int -is_widget_pio_enabled(ioerror_t *ioerror) -{ - cnodeid_t src_node; - nasid_t src_nasid; - hubreg_t ii_iowa; - xwidgetnum_t widget; - iopaddr_t p; - - /* Get the node where the PIO error occurred */ - IOERROR_GETVALUE(p,ioerror, srcnode); - src_node = p; - if (src_node == CNODEID_NONE) - return(0); - - /* Get the nasid for the cnode */ - src_nasid = cnodeid_to_nasid(src_node); - if (src_nasid == INVALID_NASID) - return(0); - - /* Read the Outbound widget access register for this hub */ - ii_iowa = REMOTE_HUB_L(src_nasid, IIO_IOWA); - IOERROR_GETVALUE(p,ioerror, widgetnum); - widget = p; - - /* Check if the PIOs to the widget with PIO error have been - * enabled. - */ - if (ii_iowa & IIO_IOWA_WIDGET(widget)) - return(1); - - return(0); -} - -/* - * Hub IO error handling. - * - * Gets invoked for different types of errors found at the hub. - * Typically this includes situations from bus error or due to - * an error interrupt (mostly generated at the hub). - */ -int -hub_ioerror_handler( - vertex_hdl_t hub_v, - int error_code, - int mode, - struct io_error_s *ioerror) -{ - hubinfo_t hinfo; /* Hub info pointer */ - nasid_t nasid; - int retval = 0; - /*REFERENCED*/ - iopaddr_t p; - caddr_t cp; - - hubinfo_get(hub_v, &hinfo); - - if (!hinfo){ - /* Print an error message and return */ - goto end; - } - nasid = hinfo->h_nasid; - - switch(error_code) { - - case PIO_READ_ERROR: - /* - * Cpu got a bus error while accessing IO space. - * hubaddr field in ioerror structure should have - * the IO address that caused access error. - */ - - /* - * Identify if the physical address in hub_error_data - * corresponds to small/large window, and accordingly, - * get the xtalk address. - */ - - /* - * Evaluate the widget number and the widget address that - * caused the error. Use 'vaddr' if it's there. - * This is typically true either during probing - * or a kernel driver getting into trouble. - * Otherwise, use paddr to figure out widget details - * This is typically true for user mode bus errors while - * accessing I/O space. - */ - IOERROR_GETVALUE(cp,ioerror,vaddr); - if (cp){ - /* - * If neither in small window nor in large window range, - * outright reject it. - */ - IOERROR_GETVALUE(cp,ioerror,vaddr); - if (NODE_SWIN_ADDR(nasid, (paddr_t)cp)){ - iopaddr_t hubaddr; - xwidgetnum_t widgetnum; - iopaddr_t xtalkaddr; - - IOERROR_GETVALUE(p,ioerror,hubaddr); - hubaddr = p; - widgetnum = SWIN_WIDGETNUM(hubaddr); - xtalkaddr = SWIN_WIDGETADDR(hubaddr); - /* - * differentiate local register vs IO space access - */ - IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); - IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); - - - } else if (NODE_BWIN_ADDR(nasid, (paddr_t)cp)){ - /* - * Address corresponds to large window space. - * Convert it to xtalk address. - */ - int bigwin; - hub_piomap_t bw_piomap; - xtalk_piomap_t xt_pmap = NULL; - iopaddr_t hubaddr; - xwidgetnum_t widgetnum; - iopaddr_t xtalkaddr; - - IOERROR_GETVALUE(p,ioerror,hubaddr); - hubaddr = p; - - /* - * Have to loop to find the correct xtalk_piomap - * because the're not allocated on a one-to-one - * basis to the window number. - */ - for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { - bw_piomap = hubinfo_bwin_piomap_get(hinfo, - bigwin); - - if (bw_piomap->hpio_bigwin_num == - (BWIN_WINDOWNUM(hubaddr) - 1)) { - xt_pmap = hub_piomap_xt_piomap(bw_piomap); - break; - } - } - - ASSERT(xt_pmap); - - widgetnum = xtalk_pio_target_get(xt_pmap); - xtalkaddr = xtalk_pio_xtalk_addr_get(xt_pmap) + BWIN_WIDGETADDR(hubaddr); - - IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); - IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); - - /* - * Make sure that widgetnum doesnot map to hub - * register widget number, as we never use - * big window to access hub registers. - */ - ASSERT(widgetnum != HUB_REGISTER_WIDGET); - } - } else if (IOERROR_FIELDVALID(ioerror,hubaddr)) { - iopaddr_t hubaddr; - xwidgetnum_t widgetnum; - iopaddr_t xtalkaddr; - - IOERROR_GETVALUE(p,ioerror,hubaddr); - hubaddr = p; - if (BWIN_WINDOWNUM(hubaddr)){ - int window = BWIN_WINDOWNUM(hubaddr) - 1; - hubreg_t itte; - itte = (hubreg_t)HUB_L(IIO_ITTE_GET(nasid, window)); - widgetnum = (itte >> IIO_ITTE_WIDGET_SHIFT) & - IIO_ITTE_WIDGET_MASK; - xtalkaddr = (((itte >> IIO_ITTE_OFFSET_SHIFT) & - IIO_ITTE_OFFSET_MASK) << - BWIN_SIZE_BITS) + - BWIN_WIDGETADDR(hubaddr); - } else { - widgetnum = SWIN_WIDGETNUM(hubaddr); - xtalkaddr = SWIN_WIDGETADDR(hubaddr); - } - IOERROR_SETVALUE(ioerror,widgetnum,widgetnum); - IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr); - } else { - IOERR_PRINTF(printk( - "hub_ioerror_handler: Invalid address passed")); - - return IOERROR_INVALIDADDR; - } - - - IOERROR_GETVALUE(p,ioerror,widgetnum); - if ((p) == HUB_REGISTER_WIDGET) { - /* - * Error in accessing Hub local register - * This should happen mostly in SABLE mode.. - */ - retval = 0; - } else { - /* Make sure that the outbound widget access for this - * widget is enabled. - */ - if (!is_widget_pio_enabled(ioerror)) { - return(IOERROR_HANDLED); - } - - - retval = hub_xp_error_handler( - hub_v, nasid, error_code, mode, ioerror); - - } - - IOERR_PRINTF(printk( - "hub_ioerror_handler:PIO_READ_ERROR return: %d", - retval)); - - break; - - case PIO_WRITE_ERROR: - /* - * This hub received an interrupt indicating a widget - * attached to this hub got a timeout. - * widgetnum field should be filled to indicate the - * widget that caused error. - * - * NOTE: This hub may have nothing to do with this error. - * We are here since the widget attached to the xbow - * gets its PIOs through this hub. - * - * There is nothing that can be done at this level. - * Just invoke the xtalk error handling mechanism. - */ - IOERROR_GETVALUE(p,ioerror,widgetnum); - if ((p) == HUB_REGISTER_WIDGET) { - } else { - /* Make sure that the outbound widget access for this - * widget is enabled. - */ - - if (!is_widget_pio_enabled(ioerror)) { - return(IOERROR_HANDLED); - } - - retval = hub_xp_error_handler( - hub_v, nasid, error_code, mode, ioerror); - } - break; - - case DMA_READ_ERROR: - /* - * DMA Read error always ends up generating an interrupt - * at the widget level, and never at the hub level. So, - * we don't expect to come here any time - */ - ASSERT(0); - retval = IOERROR_UNHANDLED; - break; - - case DMA_WRITE_ERROR: - /* - * DMA Write error is generated when a write by an I/O - * device could not be completed. Problem is, device is - * totally unaware of this problem, and would continue - * writing to system memory. So, hub has a way to send - * an error interrupt on the first error, and bitbucket - * all further write transactions. - * Coming here indicates that hub detected one such error, - * and we need to handle it. - * - * Hub interrupt handler would have extracted physaddr, - * widgetnum, and widgetdevice from the CRB - * - * There is nothing special to do here, since gathering - * data from crb's is done elsewhere. Just pass the - * error to xtalk layer. - */ - retval = hub_xp_error_handler(hub_v, nasid, error_code, mode, - ioerror); - break; - - default: - ASSERT(0); - return IOERROR_BADERRORCODE; - - } - - /* - * If error was not handled, we may need to take certain action - * based on the error code. - * For e.g. in case of PIO_READ_ERROR, we may need to release the - * PIO Read entry table (they are sticky after errors). - * Similarly other cases. - * - * Further Action TBD - */ -end: - if (retval == IOERROR_HWGRAPH_LOOKUP) { - /* - * If we get errors very early, we can't traverse - * the path using hardware graph. - * To handle this situation, we need a functions - * which don't depend on the hardware graph vertex to - * handle errors. This break the modularity of the - * existing code. Instead we print out the reason for - * not handling error, and return. On return, all the - * info collected would be dumped. This should provide - * sufficient info to analyse the error. - */ - printk("Unable to handle IO error: hardware graph not setup\n"); - } - - return retval; -} - -#define INFO_LBL_ERROR_STATE "error_state" - -#define v_error_state_get(v,s) \ -(hwgraph_info_get_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t *)&s)) - -#define v_error_state_set(v,s,replace) \ -(replace ? \ -hwgraph_info_replace_LBL(v,INFO_LBL_ERROR_STATE,(arbitrary_info_t)s,0) :\ -hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s)) - - -#define v_error_state_clear(v) \ -(hwgraph_info_remove_LBL(v,INFO_LBL_ERROR_STATE,0)) - -/* - * error_state_get - * Get the state of the vertex. - * Returns ERROR_STATE_INVALID on failure - * current state otherwise - */ -error_state_t -error_state_get(vertex_hdl_t v) -{ - error_state_t s; - - /* Check if we have a valid hwgraph vertex */ - if ( v == (vertex_hdl_t)0 ) - return(ERROR_STATE_NONE); - - /* Get the labelled info hanging off the vertex which corresponds - * to the state. - */ - if (v_error_state_get(v, s) != GRAPH_SUCCESS) { - return(ERROR_STATE_NONE); - } - return(s); -} - - -/* - * error_state_set - * Set the state of the vertex - * Returns ERROR_RETURN_CODE_CANNOT_SET_STATE on failure - * ERROR_RETURN_CODE_SUCCESS otherwise - */ -error_return_code_t -error_state_set(vertex_hdl_t v,error_state_t new_state) -{ - error_state_t old_state; - int replace = 1; - - /* Check if we have a valid hwgraph vertex */ - if ( v == (vertex_hdl_t)0 ) - return(ERROR_RETURN_CODE_GENERAL_FAILURE); - - - /* This means that the error state needs to be cleaned */ - if (new_state == ERROR_STATE_NONE) { - /* Make sure that we have an error state */ - if (v_error_state_get(v,old_state) == GRAPH_SUCCESS) - v_error_state_clear(v); - return(ERROR_RETURN_CODE_SUCCESS); - } - - /* Check if the state information has been set at least once - * for this vertex. - */ - if (v_error_state_get(v,old_state) != GRAPH_SUCCESS) - replace = 0; - - if (v_error_state_set(v,new_state,replace) != GRAPH_SUCCESS) { - return(ERROR_RETURN_CODE_CANNOT_SET_STATE); - } - return(ERROR_RETURN_CODE_SUCCESS); -} diff --git a/arch/ia64/sn/io/sn2/xbow.c b/arch/ia64/sn/io/sn2/xbow.c deleted file mode 100644 index 6e873527c..000000000 --- a/arch/ia64/sn/io/sn2/xbow.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * 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. - * - * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #define DEBUG 1 */ -/* #define XBOW_DEBUG 1 */ - -#define kdebug 0 - - -/* - * This file supports the Xbow chip. Main functions: initializtion, - * error handling. - */ - -/* - * each vertex corresponding to an xbow chip - * has a "fastinfo" pointer pointing at one - * of these things. - */ - -struct xbow_soft_s { - vertex_hdl_t conn; /* our connection point */ - vertex_hdl_t vhdl; /* xbow's private vertex */ - vertex_hdl_t busv; /* the xswitch vertex */ - xbow_t *base; /* PIO pointer to crossbow chip */ - char *name; /* hwgraph name */ - - xbow_link_status_t xbow_link_status[MAX_XBOW_PORTS]; - widget_cfg_t *wpio[MAX_XBOW_PORTS]; /* cached PIO pointer */ - - /* Bandwidth allocation state. Bandwidth values are for the - * destination port since contention happens there. - * Implicit mapping from xbow ports (8..f) -> (0..7) array indices. - */ - unsigned long long bw_hiwm[MAX_XBOW_PORTS]; /* hiwater mark values */ - unsigned long long bw_cur_used[MAX_XBOW_PORTS]; /* bw used currently */ -}; - -#define xbow_soft_set(v,i) hwgraph_fastinfo_set((v), (arbitrary_info_t)(i)) -#define xbow_soft_get(v) ((struct xbow_soft_s *)hwgraph_fastinfo_get((v))) - -/* - * Function Table of Contents - */ - -int xbow_attach(vertex_hdl_t); - -int xbow_widget_present(xbow_t *, int); -static int xbow_link_alive(xbow_t *, int); -vertex_hdl_t xbow_widget_lookup(vertex_hdl_t, int); - -void xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t); -static void xbow_setwidint(xtalk_intr_t); - -xswitch_reset_link_f xbow_reset_link; - -xswitch_provider_t xbow_provider = -{ - xbow_reset_link, -}; - - -static int -xbow_mmap(struct file * file, struct vm_area_struct * vma) -{ - unsigned long phys_addr; - int error; - - phys_addr = (unsigned long)file->private_data & ~0xc000000000000000; /* Mask out the Uncache bits */ - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - vma->vm_flags |= VM_RESERVED | VM_IO; - error = io_remap_page_range(vma, vma->vm_start, phys_addr, - vma->vm_end-vma->vm_start, - vma->vm_page_prot); - return(error); -} - -/* - * This is the file operation table for the pcibr driver. - * As each of the functions are implemented, put the - * appropriate function name below. - */ -struct file_operations xbow_fops = { - .owner = THIS_MODULE, - .mmap = xbow_mmap, -}; - -#ifdef XBRIDGE_REGS_SIM -/* xbow_set_simulated_regs: sets xbow regs as needed - * for powering through the boot - */ -void -xbow_set_simulated_regs(xbow_t *xbow, int port) -{ - /* - * turn on link - */ - xbow->xb_link(port).link_status = (1<<31); - /* - * and give it a live widget too - */ - xbow->xb_link(port).link_aux_status = XB_AUX_STAT_PRESENT; - /* - * zero the link control reg - */ - xbow->xb_link(port).link_control = 0x0; -} -#endif /* XBRIDGE_REGS_SIM */ - -/* - * xbow_attach: the crosstalk provider has - * determined that there is a crossbow widget - * present, and has handed us the connection - * point for that vertex. - * - * We not only add our own vertex, but add - * some "xtalk switch" data to the switch - * vertex (at the connect point's parent) if - * it does not have any. - */ - -/*ARGSUSED */ -int -xbow_attach(vertex_hdl_t conn) -{ - /*REFERENCED */ - vertex_hdl_t vhdl; - vertex_hdl_t busv; - xbow_t *xbow; - struct xbow_soft_s *soft; - int port; - xswitch_info_t info; - xtalk_intr_t intr_hdl; - char devnm[MAXDEVNAME], *s; - xbowreg_t id; - int rev; - int i; - int xbow_num; -#if DEBUG && ATTACH_DEBUG - char name[MAXDEVNAME]; -#endif - static irqreturn_t xbow_errintr_handler(int, void *, struct pt_regs *); - - -#if DEBUG && ATTACH_DEBUG - printk("%s: xbow_attach\n", vertex_to_name(conn, name, MAXDEVNAME)); -#endif - - /* - * Get a PIO pointer to the base of the crossbow - * chip. - */ -#ifdef XBRIDGE_REGS_SIM - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: allocating %ld bytes for xbow_s\n", sizeof(xbow_t)); - xbow = (xbow_t *) kmalloc(sizeof(xbow_t), GFP_KERNEL); - if (!xbow) - return -ENOMEM; - /* - * turn on ports e and f like in a real live ibrick - */ - xbow_set_simulated_regs(xbow, 0xe); - xbow_set_simulated_regs(xbow, 0xf); -#else - xbow = (xbow_t *) xtalk_piotrans_addr(conn, 0, 0, sizeof(xbow_t), 0); -#endif /* XBRIDGE_REGS_SIM */ - - /* - * Locate the "switch" vertex: it is the parent - * of our connection point. - */ - busv = hwgraph_connectpt_get(conn); -#if DEBUG && ATTACH_DEBUG - printk("xbow_attach: Bus Vertex 0x%p, conn 0x%p, xbow register 0x%p wid= 0x%x\n", busv, conn, xbow, *(volatile u32 *)xbow); -#endif - - ASSERT(busv != GRAPH_VERTEX_NONE); - - /* - * Create our private vertex, and connect our - * driver information to it. This makes it possible - * for diagnostic drivers to open the crossbow - * vertex for access to registers. - */ - - /* - * Register a xbow driver with hwgraph. - * file ops. - */ - vhdl = hwgraph_register(conn, EDGE_LBL_XBOW, 0, - 0, 0, 0, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0, - (struct file_operations *)&xbow_fops, (void *)xbow); - if (!vhdl) { - printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n", - (void *)conn); - } - - /* - * Allocate the soft state structure and attach - * it to the xbow's vertex - */ - soft = kmalloc(sizeof(*soft), GFP_KERNEL); - if (!soft) - return -ENOMEM; - soft->conn = conn; - soft->vhdl = vhdl; - soft->busv = busv; - soft->base = xbow; - /* does the universe really need another macro? */ - /* xbow_soft_set(vhdl, (arbitrary_info_t) soft); */ - /* hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) soft); */ - -#define XBOW_NUM_SUFFIX_FORMAT "[xbow# %d]" - - /* Add xbow number as a suffix to the hwgraph name of the xbow. - * This is helpful while looking at the error/warning messages. - */ - xbow_num = 0; - - /* - * get the name of this xbow vertex and keep the info. - * This is needed during errors and interupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(vhdl, devnm, MAXDEVNAME); - soft->name = kmalloc(strlen(s) + strlen(XBOW_NUM_SUFFIX_FORMAT) + 1, - GFP_KERNEL); - if (!soft->name) { - kfree(soft); - return -ENOMEM; - } - sprintf(soft->name,"%s"XBOW_NUM_SUFFIX_FORMAT, s,xbow_num); - -#ifdef XBRIDGE_REGS_SIM - /* my o200/ibrick has id=0x2d002049, but XXBOW_WIDGET_PART_NUM is defined - * as 0xd000, so I'm using that for the partnum bitfield. - */ - printk("xbow_attach: XBRIDGE_REGS_SIM FIXME: need xb_wid_id value!!\n"); - id = 0x2d000049; -#else - id = xbow->xb_wid_id; -#endif /* XBRIDGE_REGS_SIM */ - rev = XWIDGET_PART_REV_NUM(id); - -#define XBOW_16_BIT_PORT_BW_MAX (800 * 1000 * 1000) /* 800 MB/s */ - - /* Set bandwidth hiwatermark and current values */ - for (i = 0; i < MAX_XBOW_PORTS; i++) { - soft->bw_hiwm[i] = XBOW_16_BIT_PORT_BW_MAX; /* for now */ - soft->bw_cur_used[i] = 0; - } - - /* - * attach the crossbow error interrupt. - */ - intr_hdl = xtalk_intr_alloc(conn, (device_desc_t)0, vhdl); - ASSERT(intr_hdl != NULL); - - { - int irq = ((hub_intr_t)intr_hdl)->i_bit; - int cpu = ((hub_intr_t)intr_hdl)->i_cpuid; - - intr_unreserve_level(cpu, irq); - ((hub_intr_t)intr_hdl)->i_bit = SGI_XBOW_ERROR; - } - - xtalk_intr_connect(intr_hdl, - (intr_func_t) xbow_errintr_handler, - (intr_arg_t) soft, - (xtalk_intr_setfunc_t) xbow_setwidint, - (void *) xbow); - - request_irq(SGI_XBOW_ERROR, (void *)xbow_errintr_handler, SA_SHIRQ, "XBOW error", - (intr_arg_t) soft); - - - /* - * Enable xbow error interrupts - */ - xbow->xb_wid_control = (XB_WID_CTRL_REG_ACC_IE | XB_WID_CTRL_XTALK_IE); - - /* - * take a census of the widgets present, - * leaving notes at the switch vertex. - */ - info = xswitch_info_new(busv); - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; ++port) { - if (!xbow_link_alive(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is not alive\n", - (void *)busv, port); -#endif - continue; - } - if (!xbow_widget_present(xbow, port)) { -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d is alive but no widget is present\n", (void *)busv, port); -#endif - continue; - } -#if DEBUG && XBOW_DEBUG - printk(KERN_INFO "0x%p link %d has a widget\n", - (void *)busv, port); -#endif - - xswitch_info_link_is_ok(info, port); - /* - * Turn some error interrupts on - * and turn others off. The PROM has - * some things turned on we don't - * want to see (bandwidth allocation - * errors for instance); so if it - * is not listed here, it is not on. - */ - xbow->xb_link(port).link_control = - ( (xbow->xb_link(port).link_control - /* - * Turn off these bits; they are non-fatal, - * but we might want to save some statistics - * on the frequency of these errors. - * XXX FIXME XXX - */ - & ~XB_CTRL_RCV_CNT_OFLOW_IE - & ~XB_CTRL_XMT_CNT_OFLOW_IE - & ~XB_CTRL_BNDWDTH_ALLOC_IE - & ~XB_CTRL_RCV_IE) - /* - * These are the ones we want to turn on. - */ - | (XB_CTRL_ILLEGAL_DST_IE - | XB_CTRL_OALLOC_IBUF_IE - | XB_CTRL_XMT_MAX_RTRY_IE - | XB_CTRL_MAXREQ_TOUT_IE - | XB_CTRL_XMT_RTRY_IE - | XB_CTRL_SRC_TOUT_IE) ); - } - - xswitch_provider_register(busv, &xbow_provider); - - return 0; /* attach successful */ -} - -/* - * xbow_widget_present: See if a device is present - * on the specified port of this crossbow. - */ -int -xbow_widget_present(xbow_t *xbow, int port) -{ - if ( IS_RUNNING_ON_SIMULATOR() ) { - if ( (port == 14) || (port == 15) ) { - return 1; - } - else { - return 0; - } - } - else { - /* WAR: port 0xf on PIC is missing present bit */ - if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) && - IS_PIC_XBOW(xbow->xb_wid_id) && port==0xf) { - return 1; - } - else if ( IS_PIC_XBOW(xbow->xb_wid_id) && port==0xb ) { - /* for opus the present bit doesn't work on port 0xb */ - return 1; - } - return xbow->xb_link(port).link_aux_status & XB_AUX_STAT_PRESENT; - } -} - -static int -xbow_link_alive(xbow_t * xbow, int port) -{ - xbwX_stat_t xbow_linkstat; - - xbow_linkstat.linkstatus = xbow->xb_link(port).link_status; - return (xbow_linkstat.link_alive); -} - -/* - * xbow_widget_lookup - * Lookup the edges connected to the xbow specified, and - * retrieve the handle corresponding to the widgetnum - * specified. - * If not found, return 0. - */ -vertex_hdl_t -xbow_widget_lookup(vertex_hdl_t vhdl, - int widgetnum) -{ - xswitch_info_t xswitch_info; - vertex_hdl_t conn; - - xswitch_info = xswitch_info_get(vhdl); - conn = xswitch_info_vhdl_get(xswitch_info, widgetnum); - return conn; -} - -/* - * xbow_setwidint: called when xtalk - * is establishing or migrating our - * interrupt service. - */ -static void -xbow_setwidint(xtalk_intr_t intr) -{ - xwidgetnum_t targ = xtalk_intr_target_get(intr); - iopaddr_t addr = xtalk_intr_addr_get(intr); - xtalk_intr_vector_t vect = xtalk_intr_vector_get(intr); - xbow_t *xbow = (xbow_t *) xtalk_intr_sfarg_get(intr); - - xbow_intr_preset((void *) xbow, 0, targ, addr, vect); -} - -/* - * xbow_intr_preset: called during mlreset time - * if the platform specific code needs to route - * an xbow interrupt before the xtalk infrastructure - * is available for use. - * - * Also called from xbow_setwidint, so we don't - * replicate the guts of the routine. - * - * XXX- probably should be renamed xbow_wid_intr_set or - * something to reduce confusion. - */ -/*ARGSUSED3 */ -void -xbow_intr_preset(void *which_widget, - int which_widget_intr, - xwidgetnum_t targ, - iopaddr_t addr, - xtalk_intr_vector_t vect) -{ - xbow_t *xbow = (xbow_t *) which_widget; - - xbow->xb_wid_int_upper = ((0xFF000000 & (vect << 24)) | - (0x000F0000 & (targ << 16)) | - XTALK_ADDR_TO_UPPER(addr)); - xbow->xb_wid_int_lower = XTALK_ADDR_TO_LOWER(addr); - -} - -#define XEM_ADD_STR(s) printk("%s", (s)) -#define XEM_ADD_NVAR(n,v) printk("\t%20s: 0x%llx\n", (n), ((unsigned long long)v)) -#define XEM_ADD_VAR(v) XEM_ADD_NVAR(#v,(v)) -#define XEM_ADD_IOEF(p,n) if (IOERROR_FIELDVALID(ioe,n)) { \ - IOERROR_GETVALUE(p,ioe,n); \ - XEM_ADD_NVAR("ioe." #n, p); \ - } - -int -xbow_xmit_retry_error(struct xbow_soft_s *soft, - int port) -{ - xswitch_info_t info; - vertex_hdl_t vhdl; - widget_cfg_t *wid; - widgetreg_t id; - int part; - int mfgr; - - wid = soft->wpio[port - BASE_XBOW_PORT]; - if (wid == NULL) { - /* If we can't track down a PIO - * pointer to our widget yet, - * leave our caller knowing that - * we are interested in this - * interrupt if it occurs in - * the future. - */ - info = xswitch_info_get(soft->busv); - if (!info) - return 1; - vhdl = xswitch_info_vhdl_get(info, port); - if (vhdl == GRAPH_VERTEX_NONE) - return 1; - wid = (widget_cfg_t *) xtalk_piotrans_addr - (vhdl, 0, 0, sizeof *wid, 0); - if (!wid) - return 1; - soft->wpio[port - BASE_XBOW_PORT] = wid; - } - id = wid->w_id; - part = XWIDGET_PART_NUM(id); - mfgr = XWIDGET_MFG_NUM(id); - - return 0; -} - -/* - * xbow_errintr_handler will be called if the xbow - * sends an interrupt request to report an error. - */ -static irqreturn_t -xbow_errintr_handler(int irq, void *arg, struct pt_regs *ep) -{ - ioerror_t ioe[1]; - struct xbow_soft_s *soft = (struct xbow_soft_s *)arg; - xbow_t *xbow = soft->base; - xbowreg_t wid_control; - xbowreg_t wid_stat; - xbowreg_t wid_err_cmdword; - xbowreg_t wid_err_upper; - xbowreg_t wid_err_lower; - w_err_cmd_word_u wid_err; - unsigned long long wid_err_addr; - - int fatal = 0; - int dump_ioe = 0; - static int xbow_error_handler(void *, int, ioerror_mode_t, ioerror_t *); - - wid_control = xbow->xb_wid_control; - wid_stat = xbow->xb_wid_stat_clr; - wid_err_cmdword = xbow->xb_wid_err_cmdword; - wid_err_upper = xbow->xb_wid_err_upper; - wid_err_lower = xbow->xb_wid_err_lower; - xbow->xb_wid_err_cmdword = 0; - - wid_err_addr = wid_err_lower | (((iopaddr_t) wid_err_upper & WIDGET_ERR_UPPER_ADDR_ONLY) << 32); - - if (wid_stat & XB_WID_STAT_LINK_INTR_MASK) { - int port; - - wid_err.r = wid_err_cmdword; - - for (port = MAX_PORT_NUM - MAX_XBOW_PORTS; - port < MAX_PORT_NUM; port++) { - if (wid_stat & XB_WID_STAT_LINK_INTR(port)) { - xb_linkregs_t *link = &(xbow->xb_link(port)); - xbowreg_t link_control = link->link_control; - xbowreg_t link_status = link->link_status_clr; - xbowreg_t link_aux_status = link->link_aux_status; - xbowreg_t link_pend; - - link_pend = link_status & link_control & - (XB_STAT_ILLEGAL_DST_ERR - | XB_STAT_OALLOC_IBUF_ERR - | XB_STAT_RCV_CNT_OFLOW_ERR - | XB_STAT_XMT_CNT_OFLOW_ERR - | XB_STAT_XMT_MAX_RTRY_ERR - | XB_STAT_RCV_ERR - | XB_STAT_XMT_RTRY_ERR - | XB_STAT_MAXREQ_TOUT_ERR - | XB_STAT_SRC_TOUT_ERR - ); - - if (link_pend & XB_STAT_ILLEGAL_DST_ERR) { - if (wid_err.f.sidn == port) { - IOERROR_INIT(ioe); - IOERROR_SETVALUE(ioe, widgetnum, port); - IOERROR_SETVALUE(ioe, xtalkaddr, wid_err_addr); - if (IOERROR_HANDLED == - xbow_error_handler(soft, - IOECODE_DMA, - MODE_DEVERROR, - ioe)) { - link_pend &= ~XB_STAT_ILLEGAL_DST_ERR; - } else { - dump_ioe++; - } - } - } - /* Xbow/Bridge WAR: - * if the bridge signals an LLP Transmitter Retry, - * rewrite its control register. - * If someone else triggers this interrupt, - * ignore (and disable) the interrupt. - */ - if (link_pend & XB_STAT_XMT_RTRY_ERR) { - if (!xbow_xmit_retry_error(soft, port)) { - link_control &= ~XB_CTRL_XMT_RTRY_IE; - link->link_control = link_control; - link->link_control; /* stall until written */ - } - link_pend &= ~XB_STAT_XMT_RTRY_ERR; - } - if (link_pend) { - vertex_hdl_t xwidget_vhdl; - char *xwidget_name; - - /* Get the widget name corresponding to the current - * xbow link. - */ - xwidget_vhdl = xbow_widget_lookup(soft->busv,port); - xwidget_name = xwidget_name_get(xwidget_vhdl); - - printk("%s port %X[%s] XIO Bus Error", - soft->name, port, xwidget_name); - if (link_status & XB_STAT_MULTI_ERR) - XEM_ADD_STR("\tMultiple Errors\n"); - if (link_status & XB_STAT_ILLEGAL_DST_ERR) - XEM_ADD_STR("\tInvalid Packet Destination\n"); - if (link_status & XB_STAT_OALLOC_IBUF_ERR) - XEM_ADD_STR("\tInput Overallocation Error\n"); - if (link_status & XB_STAT_RCV_CNT_OFLOW_ERR) - XEM_ADD_STR("\tLLP receive error counter overflow\n"); - if (link_status & XB_STAT_XMT_CNT_OFLOW_ERR) - XEM_ADD_STR("\tLLP transmit retry counter overflow\n"); - if (link_status & XB_STAT_XMT_MAX_RTRY_ERR) - XEM_ADD_STR("\tLLP Max Transmitter Retry\n"); - if (link_status & XB_STAT_RCV_ERR) - XEM_ADD_STR("\tLLP Receiver error\n"); - if (link_status & XB_STAT_XMT_RTRY_ERR) - XEM_ADD_STR("\tLLP Transmitter Retry\n"); - if (link_status & XB_STAT_MAXREQ_TOUT_ERR) - XEM_ADD_STR("\tMaximum Request Timeout\n"); - if (link_status & XB_STAT_SRC_TOUT_ERR) - XEM_ADD_STR("\tSource Timeout Error\n"); - - { - int other_port; - - for (other_port = 8; other_port < 16; ++other_port) { - if (link_aux_status & (1 << other_port)) { - /* XXX- need to go to "other_port" - * and clean up after the timeout? - */ - XEM_ADD_VAR(other_port); - } - } - } - -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); - -#if !DEBUG - } -#endif - fatal++; - } - } - } - } - if (wid_stat & wid_control & XB_WID_STAT_WIDGET0_INTR) { - /* we have a "widget zero" problem */ - - if (wid_stat & (XB_WID_STAT_MULTI_ERR - | XB_WID_STAT_XTALK_ERR - | XB_WID_STAT_REG_ACC_ERR)) { - - printk("%s Port 0 XIO Bus Error", - soft->name); - if (wid_stat & XB_WID_STAT_MULTI_ERR) - XEM_ADD_STR("\tMultiple Error\n"); - if (wid_stat & XB_WID_STAT_XTALK_ERR) - XEM_ADD_STR("\tXIO Error\n"); - if (wid_stat & XB_WID_STAT_REG_ACC_ERR) - XEM_ADD_STR("\tRegister Access Error\n"); - - fatal++; - } - } - if (fatal) { - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_control); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - panic("XIO Bus Error"); - } - return IRQ_HANDLED; -} - -/* - * XBOW ERROR Handling routines. - * These get invoked as part of walking down the error handling path - * from hub/heart towards the I/O device that caused the error. - */ - -/* - * xbow_error_handler - * XBow error handling dispatch routine. - * This is the primary interface used by external world to invoke - * in case of an error related to a xbow. - * Only functionality in this layer is to identify the widget handle - * given the widgetnum. Otherwise, xbow does not gathers any error - * data. - */ -static int -xbow_error_handler( - void *einfo, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - int retval = IOERROR_WIDGETLEVEL; - - struct xbow_soft_s *soft = (struct xbow_soft_s *) einfo; - int port; - vertex_hdl_t conn; - vertex_hdl_t busv; - - xbow_t *xbow = soft->base; - xbowreg_t wid_stat; - xbowreg_t wid_err_cmdword; - xbowreg_t wid_err_upper; - xbowreg_t wid_err_lower; - unsigned long long wid_err_addr; - - xb_linkregs_t *link; - xbowreg_t link_control; - xbowreg_t link_status; - xbowreg_t link_aux_status; - - ASSERT(soft != 0); - busv = soft->busv; - -#if DEBUG && ERROR_DEBUG - printk("%s: xbow_error_handler\n", soft->name, busv); -#endif - - IOERROR_GETVALUE(port, ioerror, widgetnum); - - if (port == 0) { - /* error during access to xbow: - * do NOT attempt to access xbow regs. - */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - printk(KERN_ALERT - "DMA error blamed on Crossbow at %s\n" - "\tbut Crosbow never initiates DMA!", - soft->name); - } - if (error_code & IOECODE_PIO) { - iopaddr_t tmp; - IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); - printk(KERN_ALERT "PIO Error on XIO Bus %s\n" - "\tattempting to access XIO controller\n" - "\twith offset 0x%lx", - soft->name, tmp); - } - /* caller will dump contents of ioerror - * in DEBUG and kdebug kernels. - */ - - return retval; - } - /* - * error not on port zero: - * safe to read xbow registers. - */ - wid_stat = xbow->xb_wid_stat; - wid_err_cmdword = xbow->xb_wid_err_cmdword; - wid_err_upper = xbow->xb_wid_err_upper; - wid_err_lower = xbow->xb_wid_err_lower; - - wid_err_addr = - wid_err_lower - | (((iopaddr_t) wid_err_upper - & WIDGET_ERR_UPPER_ADDR_ONLY) - << 32); - - if ((port < BASE_XBOW_PORT) || - (port >= MAX_PORT_NUM)) { - - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - printk(KERN_ALERT - "DMA error blamed on XIO port at %s/%d\n" - "\tbut Crossbow does not support that port", - soft->name, port); - } - if (error_code & IOECODE_PIO) { - iopaddr_t tmp; - IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); - printk(KERN_ALERT - "PIO Error on XIO Bus %s\n" - "\tattempting to access XIO port %d\n" - "\t(which Crossbow does not support)" - "\twith offset 0x%lx", - soft->name, port, tmp); - } -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); -#if !DEBUG - } -#endif - - /* caller will dump contents of ioerror - * in DEBUG and kdebug kernels. - */ - - return retval; - } - /* access to valid port: - * ok to check port status. - */ - - link = &(xbow->xb_link(port)); - link_control = link->link_control; - link_status = link->link_status; - link_aux_status = link->link_aux_status; - - /* Check that there is something present - * in that XIO port. - */ - /* WAR: PIC widget 0xf is missing prescense bit */ - if (XBOW_WAR_ENABLED(PV854827, xbow->xb_wid_id) && - IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xf)) - ; - else if (IS_PIC_XBOW(xbow->xb_wid_id) && (port==0xb)) - ; /* WAR for opus this is missing on 0xb */ - else if (!(link_aux_status & XB_AUX_STAT_PRESENT)) { - /* nobody connected. */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (error_code & IOECODE_DMA) { - printk(KERN_ALERT - "DMA error blamed on XIO port at %s/%d\n" - "\tbut there is no device connected there.", - soft->name, port); - } - if (error_code & IOECODE_PIO) { - iopaddr_t tmp; - IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); - printk(KERN_ALERT - "PIO Error on XIO Bus %s\n" - "\tattempting to access XIO port %d\n" - "\t(which has no device connected)" - "\twith offset 0x%lx", - soft->name, port, tmp); - } -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - XEM_ADD_VAR(port); - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); -#if !DEBUG - } -#endif - return retval; - - } - /* Check that the link is alive. - */ - if (!(link_status & XB_STAT_LINKALIVE)) { - iopaddr_t tmp; - /* nobody connected. */ - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - printk(KERN_ALERT - "%s%sError on XIO Bus %s port %d", - (error_code & IOECODE_DMA) ? "DMA " : "", - (error_code & IOECODE_PIO) ? "PIO " : "", - soft->name, port); - - IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); - if ((error_code & IOECODE_PIO) && - (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - printk("\tAccess attempted to offset 0x%lx\n", tmp); - } - if (link_aux_status & XB_AUX_LINKFAIL_RST_BAD) - XEM_ADD_STR("\tLink never came out of reset\n"); - else - XEM_ADD_STR("\tLink failed while transferring data\n"); - - } - /* get the connection point for the widget - * involved in this error; if it exists and - * is not our connectpoint, cycle back through - * xtalk_error_handler to deliver control to - * the proper handler (or to report a generic - * crosstalk error). - * - * If the downstream handler won't handle - * the problem, we let our upstream caller - * deal with it, after (in DEBUG and kdebug - * kernels) dumping the xbow state for this - * port. - */ - conn = xbow_widget_lookup(busv, port); - if ((conn != GRAPH_VERTEX_NONE) && - (conn != soft->conn)) { - retval = xtalk_error_handler(conn, error_code, mode, ioerror); - if (retval == IOERROR_HANDLED) - return IOERROR_HANDLED; - } - if (mode == MODE_DEVPROBE) - return IOERROR_HANDLED; - - if (retval == IOERROR_UNHANDLED) { - iopaddr_t tmp; - retval = IOERROR_PANIC; - - printk(KERN_ALERT - "%s%sError on XIO Bus %s port %d", - (error_code & IOECODE_DMA) ? "DMA " : "", - (error_code & IOECODE_PIO) ? "PIO " : "", - soft->name, port); - - IOERROR_GETVALUE(tmp, ioerror, xtalkaddr); - if ((error_code & IOECODE_PIO) && - (IOERROR_FIELDVALID(ioerror, xtalkaddr))) { - printk("\tAccess attempted to offset 0x%lx\n", tmp); - } - } - -#if !DEBUG - if (kdebug) { -#endif - XEM_ADD_STR("Raw status values for Crossbow:\n"); - XEM_ADD_VAR(wid_stat); - XEM_ADD_VAR(wid_err_cmdword); - XEM_ADD_VAR(wid_err_upper); - XEM_ADD_VAR(wid_err_lower); - XEM_ADD_VAR(wid_err_addr); - XEM_ADD_VAR(port); - XEM_ADD_VAR(link_control); - XEM_ADD_VAR(link_status); - XEM_ADD_VAR(link_aux_status); -#if !DEBUG - } -#endif - /* caller will dump raw ioerror data - * in DEBUG and kdebug kernels. - */ - - return retval; -} - -int -xbow_reset_link(vertex_hdl_t xconn_vhdl) -{ - xwidget_info_t widget_info; - xwidgetnum_t port; - xbow_t *xbow; - xbowreg_t ctrl; - xbwX_stat_t stat; - unsigned long itick; - unsigned int dtick; - static long ticks_to_wait = HZ / 1000; - - widget_info = xwidget_info_get(xconn_vhdl); - port = xwidget_info_id_get(widget_info); - -#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ - xbow = XBOW_K1PTR; -#else - { - vertex_hdl_t xbow_vhdl; - struct xbow_soft_s *xbow_soft; - - hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); - xbow_soft = xbow_soft_get(xbow_vhdl); - xbow = xbow_soft->base; - } -#endif - - /* - * This requires three PIOs (reset the link, check for the - * reset, restore the control register for the link) plus - * 10us to wait for the reset. We allow up to 1ms for the - * widget to come out of reset before giving up and - * returning a failure. - */ - ctrl = xbow->xb_link(port).link_control; - xbow->xb_link(port).link_reset = 0; - itick = jiffies; - while (1) { - stat.linkstatus = xbow->xb_link(port).link_status; - if (stat.link_alive) - break; - dtick = jiffies - itick; - if (dtick > ticks_to_wait) { - return -1; /* never came out of reset */ - } - udelay(2); /* don't beat on link_status */ - } - xbow->xb_link(port).link_control = ctrl; - return 0; -} diff --git a/arch/ia64/sn/io/sn2/xtalk.c b/arch/ia64/sn/io/sn2/xtalk.c deleted file mode 100644 index 4e9769cfb..000000000 --- a/arch/ia64/sn/io/sn2/xtalk.c +++ /dev/null @@ -1,927 +0,0 @@ -/* - * 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. - * - * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Implement io channel provider operations. The xtalk* layer provides a - * platform-independent interface for io channel devices. This layer - * switches among the possible implementations of a io channel adapter. - * - * On platforms with only one possible xtalk provider, macros can be - * set up at the top that cause the table lookups and indirections to - * completely disappear. - */ - -char widget_info_fingerprint[] = "widget_info"; - -/* ===================================================================== - * Function Table of Contents - */ -xtalk_piomap_t xtalk_piomap_alloc(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, size_t, unsigned); -void xtalk_piomap_free(xtalk_piomap_t); -caddr_t xtalk_piomap_addr(xtalk_piomap_t, iopaddr_t, size_t); -void xtalk_piomap_done(xtalk_piomap_t); -caddr_t xtalk_piotrans_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, unsigned); -caddr_t xtalk_pio_addr(vertex_hdl_t, device_desc_t, iopaddr_t, size_t, xtalk_piomap_t *, unsigned); -void xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *); -caddr_t xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -static caddr_t null_xtalk_early_piotrans_addr(xwidget_part_num_t, xwidget_mfg_num_t, int, iopaddr_t, size_t, unsigned); -xtalk_dmamap_t xtalk_dmamap_alloc(vertex_hdl_t, device_desc_t, size_t, unsigned); -void xtalk_dmamap_free(xtalk_dmamap_t); -iopaddr_t xtalk_dmamap_addr(xtalk_dmamap_t, paddr_t, size_t); -void xtalk_dmamap_done(xtalk_dmamap_t); -iopaddr_t xtalk_dmatrans_addr(vertex_hdl_t, device_desc_t, paddr_t, size_t, unsigned); -void xtalk_dmamap_drain(xtalk_dmamap_t); -void xtalk_dmaaddr_drain(vertex_hdl_t, iopaddr_t, size_t); -xtalk_intr_t xtalk_intr_alloc(vertex_hdl_t, device_desc_t, vertex_hdl_t); -xtalk_intr_t xtalk_intr_alloc_nothd(vertex_hdl_t, device_desc_t, vertex_hdl_t); -void xtalk_intr_free(xtalk_intr_t); -int xtalk_intr_connect(xtalk_intr_t, intr_func_t, intr_arg_t, xtalk_intr_setfunc_t, void *); -void xtalk_intr_disconnect(xtalk_intr_t); -vertex_hdl_t xtalk_intr_cpu_get(xtalk_intr_t); -int xtalk_error_handler(vertex_hdl_t, int, ioerror_mode_t, ioerror_t *); -void xtalk_provider_startup(vertex_hdl_t); -void xtalk_provider_shutdown(vertex_hdl_t); -vertex_hdl_t xtalk_intr_dev_get(xtalk_intr_t); -xwidgetnum_t xtalk_intr_target_get(xtalk_intr_t); -xtalk_intr_vector_t xtalk_intr_vector_get(xtalk_intr_t); -iopaddr_t xtalk_intr_addr_get(struct xtalk_intr_s *); -void *xtalk_intr_sfarg_get(xtalk_intr_t); -vertex_hdl_t xtalk_pio_dev_get(xtalk_piomap_t); -xwidgetnum_t xtalk_pio_target_get(xtalk_piomap_t); -iopaddr_t xtalk_pio_xtalk_addr_get(xtalk_piomap_t); -ulong xtalk_pio_mapsz_get(xtalk_piomap_t); -caddr_t xtalk_pio_kvaddr_get(xtalk_piomap_t); -vertex_hdl_t xtalk_dma_dev_get(xtalk_dmamap_t); -xwidgetnum_t xtalk_dma_target_get(xtalk_dmamap_t); -xwidget_info_t xwidget_info_chk(vertex_hdl_t); -xwidget_info_t xwidget_info_get(vertex_hdl_t); -void xwidget_info_set(vertex_hdl_t, xwidget_info_t); -vertex_hdl_t xwidget_info_dev_get(xwidget_info_t); -xwidgetnum_t xwidget_info_id_get(xwidget_info_t); -vertex_hdl_t xwidget_info_master_get(xwidget_info_t); -xwidgetnum_t xwidget_info_masterid_get(xwidget_info_t); -xwidget_part_num_t xwidget_info_part_num_get(xwidget_info_t); -xwidget_mfg_num_t xwidget_info_mfg_num_get(xwidget_info_t); -char *xwidget_info_name_get(xwidget_info_t); -void xtalk_provider_register(vertex_hdl_t, xtalk_provider_t *); -void xtalk_provider_unregister(vertex_hdl_t); -xtalk_provider_t *xtalk_provider_fns_get(vertex_hdl_t); -int xwidget_driver_register(xwidget_part_num_t, - xwidget_mfg_num_t, - char *, unsigned); -void xwidget_driver_unregister(char *); -int xwidget_register(xwidget_hwid_t, vertex_hdl_t, - xwidgetnum_t, vertex_hdl_t, - xwidgetnum_t); -int xwidget_unregister(vertex_hdl_t); -void xwidget_reset(vertex_hdl_t); -char *xwidget_name_get(vertex_hdl_t); -#if !defined(DEV_FUNC) -/* - * There is more than one possible provider - * for this platform. We need to examine the - * master vertex of the current vertex for - * a provider function structure, and indirect - * through the appropriately named member. - */ -#define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func -#define CAST_PIOMAP(x) ((xtalk_piomap_t)(x)) -#define CAST_DMAMAP(x) ((xtalk_dmamap_t)(x)) -#define CAST_INTR(x) ((xtalk_intr_t)(x)) -xtalk_provider_t * xwidget_info_pops_get(xwidget_info_t info); - -static xtalk_provider_t * -xwidget_to_provider_fns(vertex_hdl_t xconn) -{ - xwidget_info_t widget_info; - xtalk_provider_t *provider_fns; - - widget_info = xwidget_info_get(xconn); - ASSERT(widget_info != NULL); - - provider_fns = xwidget_info_pops_get(widget_info); - ASSERT(provider_fns != NULL); - - return (provider_fns); -} - -xtalk_provider_t * -xwidget_info_pops_get(xwidget_info_t info) { - vertex_hdl_t master = info->w_master; - xtalk_provider_t *provider_fns; - - provider_fns = xtalk_provider_fns_get(master); - - ASSERT(provider_fns != NULL); - return provider_fns; -} -#endif - -/* - * Many functions are not passed their vertex - * information directly; rather, they must - * dive through a resource map. These macros - * are available to coordinate this detail. - */ -#define PIOMAP_FUNC(map,func) DEV_FUNC(map->xp_dev,func) -#define DMAMAP_FUNC(map,func) DEV_FUNC(map->xd_dev,func) -#define INTR_FUNC(intr,func) DEV_FUNC(intr_hdl->xi_dev,func) - -/* ===================================================================== - * PIO MANAGEMENT - * - * For mapping system virtual address space to - * xtalk space on a specified widget - */ - -xtalk_piomap_t -xtalk_piomap_alloc(vertex_hdl_t dev, /* set up mapping for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ - size_t byte_count, - size_t byte_count_max, /* maximum size of a mapping */ - unsigned flags) -{ /* defined in sys/pio.h */ - return (xtalk_piomap_t) DEV_FUNC(dev, piomap_alloc) - (dev, dev_desc, xtalk_addr, byte_count, byte_count_max, flags); -} - - -void -xtalk_piomap_free(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_free) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piomap_addr(xtalk_piomap_t xtalk_piomap, /* mapping resources */ - iopaddr_t xtalk_addr, /* map for this xtalk address */ - size_t byte_count) -{ /* map this many bytes */ - return PIOMAP_FUNC(xtalk_piomap, piomap_addr) - (CAST_PIOMAP(xtalk_piomap), xtalk_addr, byte_count); -} - - -void -xtalk_piomap_done(xtalk_piomap_t xtalk_piomap) -{ - PIOMAP_FUNC(xtalk_piomap, piomap_done) - (CAST_PIOMAP(xtalk_piomap)); -} - - -caddr_t -xtalk_piotrans_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t xtalk_addr, /* Crosstalk address */ - size_t byte_count, /* map this many bytes */ - unsigned flags) -{ /* (currently unused) */ - return DEV_FUNC(dev, piotrans_addr) - (dev, dev_desc, xtalk_addr, byte_count, flags); -} - -caddr_t -xtalk_pio_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - iopaddr_t addr, /* starting address (or offset in window) */ - size_t byte_count, /* map this many bytes */ - xtalk_piomap_t *mapp, /* where to return the map pointer */ - unsigned flags) -{ /* PIO flags */ - xtalk_piomap_t map = 0; - caddr_t res; - - if (mapp) - *mapp = 0; /* record "no map used" */ - - res = xtalk_piotrans_addr - (dev, dev_desc, addr, byte_count, flags); - if (res) - return res; /* xtalk_piotrans worked */ - - map = xtalk_piomap_alloc - (dev, dev_desc, addr, byte_count, byte_count, flags); - if (!map) - return res; /* xtalk_piomap_alloc failed */ - - res = xtalk_piomap_addr - (map, addr, byte_count); - if (!res) { - xtalk_piomap_free(map); - return res; /* xtalk_piomap_addr failed */ - } - if (mapp) - *mapp = map; /* pass back map used */ - - return res; /* xtalk_piomap_addr succeeded */ -} - -/* ===================================================================== - * EARLY PIOTRANS SUPPORT - * - * There are places where drivers (mgras, for instance) - * need to get PIO translations before the infrastructure - * is extended to them (setting up textports, for - * instance). These drivers should call - * xtalk_early_piotrans_addr with their xtalk ID - * information, a sequence number (so we can use the second - * mgras for instance), and the usual piotrans parameters. - * - * Machine specific code should provide an implementation - * of early_piotrans_addr, and present a pointer to this - * function to xtalk_set_early_piotrans_addr so it can be - * used by clients without the clients having to know what - * platform or what xtalk provider is in use. - */ - -static xtalk_early_piotrans_addr_f null_xtalk_early_piotrans_addr; - -xtalk_early_piotrans_addr_f *impl_early_piotrans_addr = null_xtalk_early_piotrans_addr; - -/* xtalk_set_early_piotrans_addr: - * specify the early_piotrans_addr implementation function. - */ -void -xtalk_set_early_piotrans_addr(xtalk_early_piotrans_addr_f *impl) -{ - impl_early_piotrans_addr = impl; -} - -/* xtalk_early_piotrans_addr: - * figure out a PIO address for the "nth" io channel widget that - * matches the specified part and mfgr number. Returns NULL if - * there is no such widget, or if the requested mapping can not - * be constructed. - * Limitations on which io channel slots (and busses) are - * checked, and definitions of the ordering of the search across - * the io channel slots, are defined by the platform. - */ -caddr_t -xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ - return impl_early_piotrans_addr - (part_num, mfg_num, which, xtalk_addr, byte_count, flags); -} - -/* null_xtalk_early_piotrans_addr: - * used as the early_piotrans_addr implementation until and - * unless a real implementation is provided. In DEBUG kernels, - * we want to know who is calling before the implementation is - * registered; in non-DEBUG kernels, return NULL representing - * lack of mapping support. - */ -/*ARGSUSED */ -static caddr_t -null_xtalk_early_piotrans_addr(xwidget_part_num_t part_num, - xwidget_mfg_num_t mfg_num, - int which, - iopaddr_t xtalk_addr, - size_t byte_count, - unsigned flags) -{ -#if DEBUG - panic("null_xtalk_early_piotrans_addr"); -#endif - return NULL; -} - -/* ===================================================================== - * DMA MANAGEMENT - * - * For mapping from io channel space to system - * physical space. - */ - -xtalk_dmamap_t -xtalk_dmamap_alloc(vertex_hdl_t dev, /* set up mappings for this device */ - device_desc_t dev_desc, /* device descriptor */ - size_t byte_count_max, /* max size of a mapping */ - unsigned flags) -{ /* defined in dma.h */ - return (xtalk_dmamap_t) DEV_FUNC(dev, dmamap_alloc) - (dev, dev_desc, byte_count_max, flags); -} - - -void -xtalk_dmamap_free(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_free) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmamap_addr(xtalk_dmamap_t xtalk_dmamap, /* use these mapping resources */ - paddr_t paddr, /* map for this address */ - size_t byte_count) -{ /* map this many bytes */ - return DMAMAP_FUNC(xtalk_dmamap, dmamap_addr) - (CAST_DMAMAP(xtalk_dmamap), paddr, byte_count); -} - - -void -xtalk_dmamap_done(xtalk_dmamap_t xtalk_dmamap) -{ - DMAMAP_FUNC(xtalk_dmamap, dmamap_done) - (CAST_DMAMAP(xtalk_dmamap)); -} - - -iopaddr_t -xtalk_dmatrans_addr(vertex_hdl_t dev, /* translate for this device */ - device_desc_t dev_desc, /* device descriptor */ - paddr_t paddr, /* system physical address */ - size_t byte_count, /* length */ - unsigned flags) -{ /* defined in dma.h */ - return DEV_FUNC(dev, dmatrans_addr) - (dev, dev_desc, paddr, byte_count, flags); -} - - -void -xtalk_dmamap_drain(xtalk_dmamap_t map) -{ - DMAMAP_FUNC(map, dmamap_drain) - (CAST_DMAMAP(map)); -} - -void -xtalk_dmaaddr_drain(vertex_hdl_t dev, paddr_t addr, size_t size) -{ - DEV_FUNC(dev, dmaaddr_drain) - (dev, addr, size); -} - -/* ===================================================================== - * INTERRUPT MANAGEMENT - * - * Allow io channel devices to establish interrupts - */ - -/* - * Allocate resources required for an interrupt as specified in intr_desc. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc(vertex_hdl_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - vertex_hdl_t owner_dev) -{ /* owner of this interrupt */ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc) - (dev, dev_desc, owner_dev); -} - -/* - * Allocate resources required for an interrupt as specified in dev_desc. - * Unconditionally setup resources to be non-threaded. - * Return resource handle in intr_hdl. - */ -xtalk_intr_t -xtalk_intr_alloc_nothd(vertex_hdl_t dev, /* which Crosstalk device */ - device_desc_t dev_desc, /* device descriptor */ - vertex_hdl_t owner_dev) /* owner of this interrupt */ -{ - return (xtalk_intr_t) DEV_FUNC(dev, intr_alloc_nothd) - (dev, dev_desc, owner_dev); -} - -/* - * Free resources consumed by intr_alloc. - */ -void -xtalk_intr_free(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_free) - (CAST_INTR(intr_hdl)); -} - - -/* - * Associate resources allocated with a previous xtalk_intr_alloc call with the - * described handler, arg, name, etc. - * - * Returns 0 on success, returns <0 on failure. - */ -int -xtalk_intr_connect(xtalk_intr_t intr_hdl, /* xtalk intr resource handle */ - intr_func_t intr_func, /* xtalk intr handler */ - intr_arg_t intr_arg, /* arg to intr handler */ - xtalk_intr_setfunc_t setfunc, /* func to set intr hw */ - void *setfunc_arg) /* arg to setfunc */ -{ - return INTR_FUNC(intr_hdl, intr_connect) - (CAST_INTR(intr_hdl), intr_func, intr_arg, setfunc, setfunc_arg); -} - - -/* - * Disassociate handler with the specified interrupt. - */ -void -xtalk_intr_disconnect(xtalk_intr_t intr_hdl) -{ - INTR_FUNC(intr_hdl, intr_disconnect) - (CAST_INTR(intr_hdl)); -} - - -/* - * Return a hwgraph vertex that represents the CPU currently - * targeted by an interrupt. - */ -vertex_hdl_t -xtalk_intr_cpu_get(xtalk_intr_t intr_hdl) -{ - return (vertex_hdl_t)0; -} - - -/* - * ===================================================================== - * ERROR MANAGEMENT - */ - -/* - * xtalk_error_handler: - * pass this error on to the handler registered - * at the specified xtalk connecdtion point, - * or complain about it here if there is no handler. - * - * This routine plays two roles during error delivery - * to most widgets: first, the external agent (heart, - * hub, or whatever) calls in with the error and the - * connect point representing the io channel switch, - * or whatever io channel device is directly connected - * to the agent. - * - * If there is a switch, it will generally look at the - * widget number stashed in the ioerror structure; and, - * if the error came from some widget other than the - * switch, it will call back into xtalk_error_handler - * with the connection point of the offending port. - */ -int -xtalk_error_handler( - vertex_hdl_t xconn, - int error_code, - ioerror_mode_t mode, - ioerror_t *ioerror) -{ - xwidget_info_t xwidget_info; - char name[MAXDEVNAME]; - - - xwidget_info = xwidget_info_get(xconn); - /* Make sure that xwidget_info is a valid pointer before derefencing it. - * We could come in here during very early initialization. - */ - if (xwidget_info && xwidget_info->w_efunc) - return xwidget_info->w_efunc - (xwidget_info->w_einfo, - error_code, mode, ioerror); - /* - * no error handler registered for - * the offending port. it's not clear - * what needs to be done, but reporting - * it would be a good thing, unless it - * is a mode that requires nothing. - */ - if ((mode == MODE_DEVPROBE) || (mode == MODE_DEVUSERERROR) || - (mode == MODE_DEVREENABLE)) - return IOERROR_HANDLED; - - printk(KERN_WARNING "Xbow at %s encountered Fatal error", vertex_to_name(xconn, name, MAXDEVNAME)); - - return IOERROR_UNHANDLED; -} - - -/* ===================================================================== - * CONFIGURATION MANAGEMENT - */ - -/* - * Startup an io channel provider - */ -void -xtalk_provider_startup(vertex_hdl_t xtalk_provider) -{ - ((xtalk_provider_t *) hwgraph_fastinfo_get(xtalk_provider))->provider_startup(xtalk_provider); -} - - -/* - * Shutdown an io channel provider - */ -void -xtalk_provider_shutdown(vertex_hdl_t xtalk_provider) -{ - ((xtalk_provider_t *) hwgraph_fastinfo_get(xtalk_provider))->provider_shutdown(xtalk_provider); -} - -/* - * Enable a device on a xtalk widget - */ -void -xtalk_widgetdev_enable(vertex_hdl_t xconn_vhdl, int devnum) -{ - return; -} - -/* - * Shutdown a device on a xtalk widget - */ -void -xtalk_widgetdev_shutdown(vertex_hdl_t xconn_vhdl, int devnum) -{ - return; -} - -/* - * Generic io channel functions, for use with all io channel providers - * and all io channel devices. - */ - -/* Generic io channel interrupt interfaces */ -vertex_hdl_t -xtalk_intr_dev_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_dev); -} - -xwidgetnum_t -xtalk_intr_target_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_target); -} - -xtalk_intr_vector_t -xtalk_intr_vector_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_vector); -} - -iopaddr_t -xtalk_intr_addr_get(struct xtalk_intr_s *xtalk_intr) -{ - return (xtalk_intr->xi_addr); -} - -void * -xtalk_intr_sfarg_get(xtalk_intr_t xtalk_intr) -{ - return (xtalk_intr->xi_sfarg); -} - -/* Generic io channel pio interfaces */ -vertex_hdl_t -xtalk_pio_dev_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_dev); -} - -xwidgetnum_t -xtalk_pio_target_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_target); -} - -iopaddr_t -xtalk_pio_xtalk_addr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_xtalk_addr); -} - -ulong -xtalk_pio_mapsz_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_mapsz); -} - -caddr_t -xtalk_pio_kvaddr_get(xtalk_piomap_t xtalk_piomap) -{ - return (xtalk_piomap->xp_kvaddr); -} - - -/* Generic io channel dma interfaces */ -vertex_hdl_t -xtalk_dma_dev_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_dev); -} - -xwidgetnum_t -xtalk_dma_target_get(xtalk_dmamap_t xtalk_dmamap) -{ - return (xtalk_dmamap->xd_target); -} - - -/* Generic io channel widget information interfaces */ - -/* xwidget_info_chk: - * check to see if this vertex is a widget; - * if so, return its widget_info (if any). - * if not, return NULL. - */ -xwidget_info_t -xwidget_info_chk(vertex_hdl_t xwidget) -{ - arbitrary_info_t ainfo = 0; - - hwgraph_info_get_LBL(xwidget, INFO_LBL_XWIDGET, &ainfo); - return (xwidget_info_t) ainfo; -} - - -xwidget_info_t -xwidget_info_get(vertex_hdl_t xwidget) -{ - xwidget_info_t widget_info; - - widget_info = (xwidget_info_t) - hwgraph_fastinfo_get(xwidget); - - return (widget_info); -} - -void -xwidget_info_set(vertex_hdl_t xwidget, xwidget_info_t widget_info) -{ - if (widget_info != NULL) - widget_info->w_fingerprint = widget_info_fingerprint; - - hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) widget_info); - - /* Also, mark this vertex as an xwidget, - * and use the widget_info, so xwidget_info_chk - * can work (and be fairly efficient). - */ - hwgraph_info_add_LBL(xwidget, INFO_LBL_XWIDGET, - (arbitrary_info_t) widget_info); -} - -vertex_hdl_t -xwidget_info_dev_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_dev_get: null xwidget_info"); - return (xwidget_info->w_vertex); -} - -xwidgetnum_t -xwidget_info_id_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_id_get: null xwidget_info"); - return (xwidget_info->w_id); -} - - -vertex_hdl_t -xwidget_info_master_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_master_get: null xwidget_info"); - return (xwidget_info->w_master); -} - -xwidgetnum_t -xwidget_info_masterid_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_masterid_get: null xwidget_info"); - return (xwidget_info->w_masterid); -} - -xwidget_part_num_t -xwidget_info_part_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_part_num_get: null xwidget_info"); - return (xwidget_info->w_hwid.part_num); -} - -xwidget_mfg_num_t -xwidget_info_mfg_num_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_mfg_num_get: null xwidget_info"); - return (xwidget_info->w_hwid.mfg_num); -} -/* Extract the widget name from the widget information - * for the xtalk widget. - */ -char * -xwidget_info_name_get(xwidget_info_t xwidget_info) -{ - if (xwidget_info == NULL) - panic("xwidget_info_name_get: null xwidget_info"); - return(xwidget_info->w_name); -} -/* Generic io channel initialization interfaces */ - -/* - * Associate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_register(vertex_hdl_t provider, xtalk_provider_t *xtalk_fns) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t) xtalk_fns); -} - -/* - * Disassociate a set of xtalk_provider functions with a vertex. - */ -void -xtalk_provider_unregister(vertex_hdl_t provider) -{ - hwgraph_fastinfo_set(provider, (arbitrary_info_t)NULL); -} - -/* - * Obtain a pointer to the xtalk_provider functions for a specified Crosstalk - * provider. - */ -xtalk_provider_t * -xtalk_provider_fns_get(vertex_hdl_t provider) -{ - return ((xtalk_provider_t *) hwgraph_fastinfo_get(provider)); -} - -/* - * Inform xtalk infrastructure that a driver is no longer available for - * handling any widgets. - */ -void -xwidget_driver_unregister(char *driver_prefix) -{ - return; -} - -/* - * Call some function with each vertex that - * might be one of this driver's attach points. - */ -void -xtalk_iterate(char *driver_prefix, - xtalk_iter_f *func) -{ -} - -/* - * xwidget_register: - * Register a xtalk device (xwidget) by doing the following. - * -allocate and initialize xwidget_info data - * -allocate a hwgraph vertex with name based on widget number (id) - * -look up the widget's initialization function and call it, - * or remember the vertex for later initialization. - * - */ -int -xwidget_register(xwidget_hwid_t hwid, /* widget's hardware ID */ - vertex_hdl_t widget, /* widget to initialize */ - xwidgetnum_t id, /* widget's target id (0..f) */ - vertex_hdl_t master, /* widget's master vertex */ - xwidgetnum_t targetid) /* master's target id (9/a) */ -{ - xwidget_info_t widget_info; - char *s,devnm[MAXDEVNAME]; - - /* Allocate widget_info and associate it with widget vertex */ - widget_info = kmalloc(sizeof(*widget_info), GFP_KERNEL); - if (!widget_info) - return - ENOMEM; - - /* Initialize widget_info */ - widget_info->w_vertex = widget; - widget_info->w_id = id; - widget_info->w_master = master; - widget_info->w_masterid = targetid; - widget_info->w_hwid = *hwid; /* structure copy */ - widget_info->w_efunc = 0; - widget_info->w_einfo = 0; - /* - * get the name of this xwidget vertex and keep the info. - * This is needed during errors and interupts, but as - * long as we have it, we can use it elsewhere. - */ - s = dev_to_name(widget,devnm,MAXDEVNAME); - widget_info->w_name = kmalloc(strlen(s) + 1, GFP_KERNEL); - strcpy(widget_info->w_name,s); - - xwidget_info_set(widget, widget_info); - - device_master_set(widget, master); - - /* - * Add pointer to async attach info -- tear down will be done when - * the particular descendant is done with the info. - */ - return cdl_add_connpt(hwid->part_num, hwid->mfg_num, - widget, 0); -} - -/* - * xwidget_unregister : - * Unregister the xtalk device and detach all its hwgraph namespace. - */ -int -xwidget_unregister(vertex_hdl_t widget) -{ - xwidget_info_t widget_info; - xwidget_hwid_t hwid; - - /* Make sure that we have valid widget information initialized */ - if (!(widget_info = xwidget_info_get(widget))) - return 1; - - hwid = &(widget_info->w_hwid); - - kfree(widget_info->w_name); - kfree(widget_info); - return 0; -} - -void -xwidget_error_register(vertex_hdl_t xwidget, - error_handler_f *efunc, - error_handler_arg_t einfo) -{ - xwidget_info_t xwidget_info; - - xwidget_info = xwidget_info_get(xwidget); - ASSERT(xwidget_info != NULL); - xwidget_info->w_efunc = efunc; - xwidget_info->w_einfo = einfo; -} - -/* - * Issue a link reset to a widget. - */ -void -xwidget_reset(vertex_hdl_t xwidget) -{ - xswitch_reset_link(xwidget); -} - - -void -xwidget_gfx_reset(vertex_hdl_t xwidget) -{ - return; -} - -#define ANON_XWIDGET_NAME "No Name" /* Default Widget Name */ - -/* Get the canonical hwgraph name of xtalk widget */ -char * -xwidget_name_get(vertex_hdl_t xwidget_vhdl) -{ - xwidget_info_t info; - - /* If we have a bogus widget handle then return - * a default anonymous widget name. - */ - if (xwidget_vhdl == GRAPH_VERTEX_NONE) - return(ANON_XWIDGET_NAME); - /* Read the widget name stored in the widget info - * for the widget setup during widget initialization. - */ - info = xwidget_info_get(xwidget_vhdl); - ASSERT(info != NULL); - return(xwidget_info_name_get(info)); -} diff --git a/arch/ia64/sn/io/snia_if.c b/arch/ia64/sn/io/snia_if.c deleted file mode 100644 index fdd738d1d..000000000 --- a/arch/ia64/sn/io/snia_if.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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. - * - * Copyright (C) 2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include - -extern pciio_provider_t *pciio_to_provider_fns(vertex_hdl_t dev); - -int -snia_badaddr_val(volatile void *addr, int len, volatile void *ptr) -{ - int ret = 0; - volatile void *new_addr; - - switch (len) { - case 4: - new_addr = (void *) addr; - ret = ia64_sn_probe_io_slot((long) new_addr, len, (void *) ptr); - break; - default: - printk(KERN_WARNING - "snia_badaddr_val given len %x but supports len of 4 only\n", - len); - } - - if (ret < 0) - panic("snia_badaddr_val: unexpected status (%d) in probing", - ret); - return (ret); - -} - -nasid_t -snia_get_console_nasid(void) -{ - extern nasid_t console_nasid; - extern nasid_t master_baseio_nasid; - - if (console_nasid < 0) { - console_nasid = ia64_sn_get_console_nasid(); - if (console_nasid < 0) { -// ZZZ What do we do if we don't get a console nasid on the hardware???? - if (IS_RUNNING_ON_SIMULATOR()) - console_nasid = master_baseio_nasid; - } - } - return console_nasid; -} - -nasid_t -snia_get_master_baseio_nasid(void) -{ - extern nasid_t master_baseio_nasid; - extern char master_baseio_wid; - - if (master_baseio_nasid < 0) { - master_baseio_nasid = ia64_sn_get_master_baseio_nasid(); - - if (master_baseio_nasid >= 0) { - master_baseio_wid = - WIDGETID_GET(KL_CONFIG_CH_CONS_INFO - (master_baseio_nasid)->memory_base); - } - } - return master_baseio_nasid; -} - -/* - * XXX: should probably be called __sn2_pci_rrb_alloc - * used by qla1280 - */ - -int -snia_pcibr_rrb_alloc(struct pci_dev *pci_dev, - int *count_vchan0, int *count_vchan1) -{ - vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); - - return pcibr_rrb_alloc(dev, count_vchan0, count_vchan1); -} - -/* - * XXX: interface should be more like - * - * int __sn2_pci_enable_bwswap(struct pci_dev *dev); - * void __sn2_pci_disable_bswap(struct pci_dev *dev); - */ -/* used by ioc4 ide */ - -pciio_endian_t -snia_pciio_endian_set(struct pci_dev * pci_dev, - pciio_endian_t device_end, pciio_endian_t desired_end) -{ - vertex_hdl_t dev = PCIDEV_VERTEX(pci_dev); - - return ((pciio_to_provider_fns(dev))->endian_set) - (dev, device_end, desired_end); -} - -EXPORT_SYMBOL(snia_pciio_endian_set); -EXPORT_SYMBOL(snia_pcibr_rrb_alloc); diff --git a/arch/ia64/sn/io/xswitch.c b/arch/ia64/sn/io/xswitch.c deleted file mode 100644 index 3284f5c4c..000000000 --- a/arch/ia64/sn/io/xswitch.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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. - * - * Copyright (c) 1992-1997,2000-2003 Silicon Graphics, Inc. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * This file provides generic support for Crosstalk - * Switches, in a way that insulates crosstalk providers - * from specifics about the switch chips being used. - */ - -#include - -#define XSWITCH_CENSUS_BIT(port) (1<<(port)) -#define XSWITCH_CENSUS_PORT_MAX (0xF) -#define XSWITCH_CENSUS_PORTS (0x10) -#define XSWITCH_WIDGET_PRESENT(infop,port) ((infop)->census & XSWITCH_CENSUS_BIT(port)) - -static char xswitch_info_fingerprint[] = "xswitch_info"; - -struct xswitch_info_s { - char *fingerprint; - unsigned census; - vertex_hdl_t vhdl[XSWITCH_CENSUS_PORTS]; - vertex_hdl_t master_vhdl[XSWITCH_CENSUS_PORTS]; - xswitch_provider_t *xswitch_fns; -}; - -xswitch_info_t -xswitch_info_get(vertex_hdl_t xwidget) -{ - xswitch_info_t xswitch_info; - - xswitch_info = (xswitch_info_t) - hwgraph_fastinfo_get(xwidget); - - return (xswitch_info); -} - -void -xswitch_info_vhdl_set(xswitch_info_t xswitch_info, - xwidgetnum_t port, - vertex_hdl_t xwidget) -{ - if (port > XSWITCH_CENSUS_PORT_MAX) - return; - - xswitch_info->vhdl[(int)port] = xwidget; -} - -vertex_hdl_t -xswitch_info_vhdl_get(xswitch_info_t xswitch_info, - xwidgetnum_t port) -{ - if (port > XSWITCH_CENSUS_PORT_MAX) - return GRAPH_VERTEX_NONE; - - return xswitch_info->vhdl[(int)port]; -} - -/* - * Some systems may allow for multiple switch masters. On such systems, - * we assign a master for each port on the switch. These interfaces - * establish and retrieve that assignment. - */ -void -xswitch_info_master_assignment_set(xswitch_info_t xswitch_info, - xwidgetnum_t port, - vertex_hdl_t master_vhdl) -{ - if (port > XSWITCH_CENSUS_PORT_MAX) - return; - - xswitch_info->master_vhdl[(int)port] = master_vhdl; -} - -vertex_hdl_t -xswitch_info_master_assignment_get(xswitch_info_t xswitch_info, - xwidgetnum_t port) -{ - if (port > XSWITCH_CENSUS_PORT_MAX) - return GRAPH_VERTEX_NONE; - - return xswitch_info->master_vhdl[(int)port]; -} - -void -xswitch_info_set(vertex_hdl_t xwidget, xswitch_info_t xswitch_info) -{ - xswitch_info->fingerprint = xswitch_info_fingerprint; - hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) xswitch_info); -} - -xswitch_info_t -xswitch_info_new(vertex_hdl_t xwidget) -{ - xswitch_info_t xswitch_info; - - xswitch_info = xswitch_info_get(xwidget); - if (xswitch_info == NULL) { - int port; - - xswitch_info = kmalloc(sizeof(*xswitch_info), GFP_KERNEL); - if (!xswitch_info) { - printk(KERN_WARNING "xswitch_info_new(): Unable to " - "allocate memory\n"); - return NULL; - } - xswitch_info->census = 0; - for (port = 0; port <= XSWITCH_CENSUS_PORT_MAX; port++) { - xswitch_info_vhdl_set(xswitch_info, port, - GRAPH_VERTEX_NONE); - - xswitch_info_master_assignment_set(xswitch_info, - port, - GRAPH_VERTEX_NONE); - } - xswitch_info_set(xwidget, xswitch_info); - } - return xswitch_info; -} - -void -xswitch_provider_register(vertex_hdl_t busv, - xswitch_provider_t * xswitch_fns) -{ - xswitch_info_t xswitch_info = xswitch_info_get(busv); - - ASSERT(xswitch_info); - xswitch_info->xswitch_fns = xswitch_fns; -} - -void -xswitch_info_link_is_ok(xswitch_info_t xswitch_info, xwidgetnum_t port) -{ - xswitch_info->census |= XSWITCH_CENSUS_BIT(port); -} - -int -xswitch_info_link_ok(xswitch_info_t xswitch_info, xwidgetnum_t port) -{ - if (port > XSWITCH_CENSUS_PORT_MAX) - return 0; - - return (xswitch_info->census & XSWITCH_CENSUS_BIT(port)); -} - -int -xswitch_reset_link(vertex_hdl_t xconn_vhdl) -{ - return xbow_reset_link(xconn_vhdl); -} diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c index 92f740477..deb9baf4d 100644 --- a/arch/ia64/sn/kernel/sn2/timer.c +++ b/arch/ia64/sn/kernel/sn2/timer.c @@ -20,6 +20,7 @@ #include extern unsigned long sn_rtc_cycles_per_second; + static struct time_interpolator sn2_interpolator = { .drift = -1, .shift = 10,