+++ /dev/null
-# 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/
+++ /dev/null
-/*
- * 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 <linux/config.h>
-#include <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/io.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/pci/pic.h>
-#include "asm/sn/ioerror_handling.h"
-#include <asm/sn/xtalk/xbow.h>
-
-/* 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/<slotnum> .. 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);
-}
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * ioconfig_bus - SGI's Persistent PCI Bus Numbering.
- *
- * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
- */
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/pci.h>
-
-#include <asm/uaccess.h>
-#include <asm/sn/sgi.h>
-#include <asm/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/ioconfig_bus.h>
-
-#define SGI_IOCONFIG_BUS "SGI-PERSISTENT PCI BUS NUMBERING"
-#define SGI_IOCONFIG_BUS_VERSION "1.0"
-
-/*
- * Some Global definitions.
- */
-static vertex_hdl_t ioconfig_bus_handle;
-static unsigned long ioconfig_bus_debug;
-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);
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/sched.h> /* needed for smp_lock.h :( */
-#include <linux/smp_lock.h>
-#include <asm/sn/sgi.h>
-#include <asm/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hwgfs.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/simulator.h>
-
-#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);
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/kernel.h>
-#include <asm/sn/sgi.h>
-#include <asm/io.h>
-#include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hwgfs.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/nodepda.h>
-
-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));
-}
-
+++ /dev/null
-/*
- * 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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/namei.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <asm/sn/hwgfs.h>
-
-
-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);
+++ /dev/null
-/* 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/sched.h> /* needed for smp_lock.h :( */
-#include <linux/smp_lock.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/hwgfs.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-
-/*
-** 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; i<num_labels; i++) {
- if (!strcmp(info_name, old_label_list[i].name)) {
- /* Not allowed to add duplicate labelled info names. */
- kfree(new_label_list);
- return(-1);
- }
- new_label_list[i] = old_label_list[i]; /* structure copy */
- }
-
- new_label_list[num_labels].name = name;
- new_label_list[num_labels].desc = info_desc;
- new_label_list[num_labels].info = info;
-
- labelcl_info->num_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; i<num_labels; i++) {
- if (!strcmp(info_name, old_label_list[i].name)) {
- label_desc_found = old_label_list[i].desc;
- label_info_found = old_label_list[i].info;
- goto found;
- }
- if (i < num_labels-1) /* avoid walking off the end of the new vertex */
- new_label_list[i] = old_label_list[i]; /* structure copy */
- }
-
- /* The named info doesn't exist. */
- if (new_label_list)
- kfree(new_label_list);
-
- return(-1);
-
-found:
- /* Finish up rest of labelled info */
- for (i=i+1; i<num_labels; i++)
- new_label_list[i-1] = old_label_list[i]; /* structure copy */
-
- labelcl_info->num_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; i<num_labels; i++)
- if (!strcmp(info_name, label_list[i].name)) {
- if (old_info != NULL)
- *old_info = label_list[i].info;
-
- if (old_info_desc != NULL)
- *old_info_desc = label_list[i].desc;
-
- label_list[i].info = info;
- label_list[i].desc = info_desc;
-
- return(0);
- }
-
-
- return(-1);
-}
-
-/*
- * labelcl_info_get_LBL - Retrieve and return the information for the
- * given label entry.
- */
-int
-labelcl_info_get_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;
- 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);
- }
-
- label_list = labelcl_info->label_list;
-
- /*
- * Find information under info_name.
- */
- for (i=0; i<num_labels; i++)
- if (!strcmp(info_name, label_list[i].name)) {
- if (info != NULL)
- *info = label_list[i].info;
- if (info_desc != NULL)
- *info_desc = label_list[i].desc;
-
- return(0);
- }
-
- return(-1);
-}
-
-/*
- * labelcl_info_get_next_LBL - returns the next label entry on the list.
- */
-int
-labelcl_info_get_next_LBL(vertex_hdl_t de,
- char *buffer,
- arb_info_desc_t *info_descp,
- arbitrary_info_t *infop,
- labelcl_info_place_t *placeptr)
-{
- labelcl_info_t *labelcl_info = NULL;
- uint which_info;
- label_info_t *label_list;
-
- if ((buffer == NULL) && (infop == NULL))
- return(-1);
-
- if (placeptr == NULL)
- return(-1);
-
- 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);
-
- 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);
-}
+++ /dev/null
-/*
- * 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 <linux/module.h>
-#include <linux/backing-dev.h>
-#include <linux/fs.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-
-/* 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)
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/driver.h>
-#include <asm/param.h>
-#include <asm/sn/pio.h>
-#include <asm/sn/xtalk/xwidget.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/xtalk/xtalkaddrs.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-
-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,
-};
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 <linux/module.h>
-#include <asm/io.h>
-#include <asm/delay.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/pda.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/sn2/shub_mmr.h>
-
-/**
- * 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);
+++ /dev/null
-/*
- * 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 <asm/sn/hcl.h>
-#include <asm/sn/pci/pcibr_private.h>
-
-/*
- * 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,
-};
+++ /dev/null
-/*
- * 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 <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/pci/pci_bus_cvlink.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/simulator.h>
-
-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; i<DEV_PER_WIDGET;i++) {
- p->bus = -1;
- p->pin = -1;
- p->slot = -1;
- p++;
- }
- }
-
- p = &flush_nasid_list[nasid].widget_p[wid_num][0];
- for (i=0;i<DEV_PER_WIDGET; i++) {
- if (p->pin == 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; i<PCI_ROM_RESOURCE; i++) {
- if (p->bar_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);
+++ /dev/null
-/*
- * 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 <linux/module.h>
-#include <asm/sn/pci/pci_bus_cvlink.h>
-
-/*
- * 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);
-
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/pda.h>
-
-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;
- }
-}
+++ /dev/null
-# 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
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/smp.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/ioerror.h>
-#include <asm/sn/sn2/shubio.h>
-#include <asm/sn/bte.h>
-
-
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn2/shub_mmr_t.h>
-#include <asm/sn/sn2/shubio.h>
-#include <asm/sal.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/module.h>
-#include <asm/sn/geo.h>
-
-/********** 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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/ctype.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/module.h>
-#include <asm/sn/router.h>
-#include <asm/sn/xtalk/xbow.h>
-#include <asm/sn/ksys/l1.h>
-
-
-#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:<serial_number>;*
- */
-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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/sn_private.h>
-
-/* #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);
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/router.h>
-#include <asm/sn/module.h>
-#include <asm/sn/ksys/l1.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/clksupport.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/sn_sal.h>
-#include <linux/ctype.h>
-
-/* 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);
- }
-}
-
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/bootmem.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/simulator.h>
-
-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;
- }
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/topology.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn2/shub_mmr_t.h>
-#include <asm/sn/sn2/shubio.h>
-#include <asm/sal.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/sn2/shub_mmr.h>
-#include <asm/sn/pda.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <linux/ctype.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/xtalk/xtalkaddrs.h>
-#include <asm/sn/ksys/l1.h>
-
-/* #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; i<num_volunteer; i++) {
- hubv = xvolinfo->xswitch_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 <asm/sn/ioerror_handling.h>
-
-/*
- * 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;
-
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/io.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/xtalk/xbow.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/module.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xswitch.h>
-#include <asm/sn/nodepda.h>
-#include <asm/sn/sn_cpuid.h>
-
-
-/* #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++;
- }
- }
-}
+++ /dev/null
-# 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
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-/*
- * 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 */
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-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;
- }
-}
+++ /dev/null
-/*
- * 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 <linux/module.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-#include <asm/sn/prio.h>
-#include <asm/sn/sn_private.h>
-
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-
-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 "<bit field descriptions>"
- * %R outputs a string of the format "0x%x<bit field descriptions>"
- *
- * 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 <device, address> 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;
- }
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/module.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/arch.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-
-#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; i<DEV_PER_WIDGET;i++) {
- for (j=0; j<PCI_ROM_RESOURCE;j++) {
- if (p->bar_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);
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-
-/*
- * 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]);
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-
-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]));
- }
- }
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/uaccess.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/sn_sal.h>
-
-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;
-}
+++ /dev/null
-/*
- * 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 <asm/sn/pci/pci_bus_cvlink.h>
-#include <asm/sn/simulator.h>
-
-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/<SLOT> ie. .../pci/3
- * multifunction: .../pci/<SLOT><FUNC> 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);
-}
+++ /dev/null
-/*
- * 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 <linux/interrupt.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/pci/pci_defs.h>
-#include <asm/sn/pci/pic.h>
-#include <asm/sn/sn_private.h>
-
-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,
-};
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/seq_file.h>
-#include <linux/sched.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/hw_irq.h>
-#include <asm/system.h>
-#include <asm/sn/sgi.h>
-#include <asm/uaccess.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/sn2/shub_mmr.h>
-#include <asm/sn/sn2/shub_mmr_t.h>
-#include <asm/sal.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/sndrv.h>
-#include <asm/sn/sn2/shubio.h>
-
-#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,
-};
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/sn/types.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/driver.h>
-#include <asm/param.h>
-#include <asm/sn/pio.h>
-#include <asm/sn/xtalk/xwidget.h>
-#include <asm/sn/io.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/xtalk/xtalkaddrs.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn2/shub_mmr.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/pci/pcibr_private.h>
-
-/* 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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/delay.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/ioerror_handling.h>
-#include <asm/sn/ioerror.h>
-#include <asm/sn/sn2/shubio.h>
-#include <asm/sn/sn2/shub_mmr.h>
-#include <asm/sn/bte.h>
-
-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;
-}
-
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/smp.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/sn_private.h>
-#include <asm/sn/klconfig.h>
-#include <asm/sn/sn_cpuid.h>
-#include <asm/sn/pci/pciio.h>
-#include <asm/sn/pci/pcibr.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/pci/pcibr_private.h>
-#include <asm/sn/intr.h>
-#include <asm/sn/ioerror_handling.h>
-#include <asm/sn/ioerror.h>
-#include <asm/sn/sn2/shubio.h>
-
-
-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);
-}
+++ /dev/null
-/*
- * 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 <linux/slab.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/sn2/sn_private.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/simulator.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/pci/pcibr_private.h>
-
-/* #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;
-}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/driver.h>
-#include <asm/sn/io.h>
-#include <asm/sn/iograph.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/hcl_util.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/xtalk/xswitch.h>
-#include <asm/sn/xtalk/xwidget.h>
-#include <asm/sn/xtalk/xtalk_private.h>
-
-/*
- * 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));
-}
+++ /dev/null
-/*
- * 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 <asm/sn/sgi.h>
-#include <asm/sn/sn_sal.h>
-#include <asm/sn/pci/pci_bus_cvlink.h>
-#include <asm/sn/simulator.h>
-
-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);
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/slab.h>
-#include <asm/errno.h>
-#include <asm/sn/sgi.h>
-#include <asm/sn/driver.h>
-#include <asm/sn/hcl.h>
-#include <asm/sn/labelcl.h>
-#include <asm/sn/xtalk/xtalk.h>
-#include <asm/sn/xtalk/xswitch.h>
-#include <asm/sn/xtalk/xwidget.h>
-#include <asm/sn/xtalk/xtalk_private.h>
-
-
-/*
- * This file provides generic support for Crosstalk
- * Switches, in a way that insulates crosstalk providers
- * from specifics about the switch chips being used.
- */
-
-#include <asm/sn/xtalk/xbow.h>
-
-#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);
-}
#include <asm/sn/clksupport.h>
extern unsigned long sn_rtc_cycles_per_second;
+
static struct time_interpolator sn2_interpolator = {
.drift = -1,
.shift = 10,