!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/arch/ia64/sn/io/   drwxr-xr-x
Free 318.32 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     xbow.c (48.62 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* $Id$
 *
 * 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 Silicon Graphics, Inc.
 * Copyright (C) 2000 by Colin Ngam
 */

#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <asm/sn/sgi.h>
#include <asm/sn/iograph.h>
#include <asm/sn/invent.h>
#include <asm/sn/hcl.h>
#include <asm/sn/labelcl.h>
#include <asm/sn/hack.h>
#include <asm/sn/pci/bridge.h>
#include <asm/sn/xtalk/xtalk_private.h>

/* #define DEBUG        1 */
/* #define XBOW_DEBUG    1 */


/*
 * Files needed to get the device driver entry points
 */

#include <asm/sn/xtalk/xbow.h>
#include <asm/sn/xtalk/xtalk.h>
#include <asm/sn/xtalk/xswitch.h>
#include <asm/sn/xtalk/xwidget.h>

#include <asm/sn/prio.h>
#include <asm/sn/hcl_util.h>


#define NEW(ptr)    (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
#define DEL(ptr)    (kfree(ptr))

int                     xbow_devflag = D_MP;

/*
 * This file supports the Xbow chip.  Main functions: initializtion,
 * error handling, and GBR.
 */

/*
 * each vertex corresponding to an xbow chip
 * has a "fastinfo" pointer pointing at one
 * of these things.
 */
typedef struct xbow_soft_s *xbow_soft_t;

struct xbow_soft_s {
    devfs_handle_t            conn;    /* our connection point */
    devfs_handle_t            vhdl;    /* xbow's private vertex */
    devfs_handle_t            busv;    /* the xswitch vertex */
    xbow_t                 *base;    /* PIO pointer to crossbow chip */
    char                   *name;    /* hwgraph name */

    xbow_perf_t             xbow_perfcnt[XBOW_PERF_COUNTERS];
    xbow_perf_link_t        xbow_perflink[MAX_XBOW_PORTS];
    xbow_link_status_t      xbow_link_status[MAX_XBOW_PORTS];
    spinlock_t              xbow_perf_lock;
    int                     link_monitor;
    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.
     */
    spinlock_t            xbow_bw_alloc_lock;        /* bw allocation lock */
    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)    ((xbow_soft_t)hwgraph_fastinfo_get((v)))

/*
 * Function Table of Contents
 */

void                    xbow_mlreset(xbow_t *);
void                    xbow_init(void);
int                     xbow_attach(devfs_handle_t);

int                     xbow_open(devfs_handle_t *, int, int, cred_t *);
int                     xbow_close(devfs_handle_t, int, int, cred_t *);

int                     xbow_map(devfs_handle_t, vhandl_t *, off_t, size_t, uint);
int                     xbow_unmap(devfs_handle_t, vhandl_t *);
int                     xbow_ioctl(devfs_handle_t, int, void *, int, struct cred *, int *);

int                     xbow_widget_present(xbow_t *, int);
static int              xbow_link_alive(xbow_t *, int);
devfs_handle_t            xbow_widget_lookup(devfs_handle_t, int);

#ifdef LATER
static void             xbow_setwidint(xtalk_intr_t);
static void             xbow_errintr_handler(intr_arg_t);
static error_handler_f  xbow_error_handler;
#endif
void                    xbow_intr_preset(void *, int, xwidgetnum_t, iopaddr_t, xtalk_intr_vector_t);



void                    xbow_update_perf_counters(devfs_handle_t);
xbow_perf_link_t       *xbow_get_perf_counters(devfs_handle_t);
int                     xbow_enable_perf_counter(devfs_handle_t, int, int, int);
xbow_link_status_t     *xbow_get_llp_status(devfs_handle_t);
void                    xbow_update_llp_status(devfs_handle_t);

int                     xbow_disable_llp_monitor(devfs_handle_t);
int                     xbow_enable_llp_monitor(devfs_handle_t);
int                     xbow_prio_bw_alloc(devfs_handle_t, xwidgetnum_t, xwidgetnum_t,
                                unsigned long long, unsigned long long);

xswitch_reset_link_f    xbow_reset_link;

void                    idbg_xbowregs(int64_t);

xswitch_provider_t      xbow_provider =
{
    xbow_reset_link,
};

/*
 *    xbow_mlreset: called at mlreset time if the
 *      platform specific code determines that there is
 *      a crossbow in a critical path that must be
 *      functional before the driver would normally get
 *      the device properly set up.
 *
 *      what do we need to do, that the boot prom can
 *      not be counted on to have already done, that is
 *      generic across all platforms using crossbows?
 */
/*ARGSUSED */
void
xbow_mlreset(xbow_t * xbow)
{
}

/*
 *    xbow_init: called with the rest of the device
 *      driver XXX_init routines. This platform *might*
 *      have a Crossbow chip, or even several, but it
 *      might have none. Register with the crosstalk
 *      generic provider so when we encounter the chip
 *      the right magic happens.
 */
void
xbow_init(void)
{

#if DEBUG && ATTACH_DEBUG
    printf("xbow_init\n");
#endif

    xwidget_driver_register(XXBOW_WIDGET_PART_NUM,
                0, /* XXBOW_WIDGET_MFGR_NUM, */
                "xbow_",
                CDL_PRI_HI);    /* attach before friends */

    xwidget_driver_register(XBOW_WIDGET_PART_NUM,
                XBOW_WIDGET_MFGR_NUM,
                "xbow_",
                CDL_PRI_HI);    /* attach before friends */
}

#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(devfs_handle_t conn)
{
    /*REFERENCED */
    devfs_handle_t            vhdl;
    devfs_handle_t            busv;
    xbow_t                 *xbow;
    xbow_soft_t             soft;
    int                     port;
    xswitch_info_t          info;
#ifdef LATER
    xtalk_intr_t            intr_hdl;
    device_desc_t           dev_desc;
#endif
    char                    devnm[MAXDEVNAME], *s;
    xbowreg_t               id;
    int                     rev;
    int                i;
    int                xbow_num;
    
#if DEBUG && ATTACH_DEBUG
#if defined(SUPPORT_PRINTING_V_FORMAT
    printk("%v: xbow_attach\n", conn);
#else
    printk("0x%x: xbow_attach\n", conn);
#endif
#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);
    /*
     * 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.
     */

    /*
     * We need to teach xbow drivers to provide the right set of
     * file ops.
     */
    vhdl = NULL;
    vhdl = hwgraph_register(conn, EDGE_LBL_XBOW,
                        0, DEVFS_FL_AUTO_DEVNUM,
                        0, 0,
                        S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
                        /* &hcl_fops */ (void *)&vhdl, NULL);
    if (!vhdl) {
        printk(KERN_WARNING "xbow_attach: Unable to create char device for xbow conn %p\n",
                conn);
    }

    /*
     * Allocate the soft state structure and attach
     * it to the xbow's vertex
     */
    NEW(soft);
    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 interrupts, 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);
    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);

    /*
     * Print the revision if DEBUG, or SHOW_REVS and kdebug,
     * or the xbow is downrev.
     *
     * If xbow is downrev, make it a WARNING that the
     * Crossbow is DOWNREV: these chips are not good
     * to have around, and the operator should be told.
     */
#ifdef    LATER
#if !DEBUG
    if (
#if SHOW_REVS
       (kdebug) ||
#endif    /* SHOW_REVS */
       (rev < XBOW_REV_1_1))
#endif    /* !DEBUG  */
    printk("%sCrossbow ASIC: rev %s (code=%d) at %s%s",
        (rev < XBOW_REV_1_1) ? "DOWNREV " : "",
        (rev == XBOW_REV_1_0) ? "1.0" :
        (rev == XBOW_REV_1_1) ? "1.1" :
        (rev == XBOW_REV_1_2) ? "1.2" :
        (rev == XBOW_REV_1_3) ? "1.3" :
        (rev == XBOW_REV_2_0) ? "2.0" :
        (rev == XXBOW_PART_REV_1_0) ? "Xbridge 1.0" :
        (rev == XXBOW_PART_REV_2_0) ? "Xbridge 2.0" :
        "unknown",
        rev, soft->name,
        (rev < XBOW_REV_1_1) ? "" : "\n");
#endif    /* LATER */
    mutex_spinlock_init(&soft->xbow_perf_lock);
    soft->xbow_perfcnt[0].xp_perf_reg = &xbow->xb_perf_ctr_a;
    soft->xbow_perfcnt[1].xp_perf_reg = &xbow->xb_perf_ctr_b;

    /* Initialization for GBR bw allocation */
    mutex_spinlock_init(&soft->xbow_bw_alloc_lock);

#define    XBOW_8_BIT_PORT_BW_MAX        (400 * 1000 * 1000)    /* 400 MB/s */
#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.
     */
#ifdef LATER
    dev_desc = device_desc_dup(vhdl);
    device_desc_flags_set(dev_desc,
              device_desc_flags_get(dev_desc) | D_INTR_ISERR);
    device_desc_intr_name_set(dev_desc, "Crossbow error");

    intr_hdl = xtalk_intr_alloc(conn, dev_desc, vhdl);
    ASSERT(intr_hdl != NULL);

    xtalk_intr_connect(intr_hdl,
               (intr_func_t) xbow_errintr_handler,
               (intr_arg_t) soft,
               (xtalk_intr_setfunc_t) xbow_setwidint,
               (void *) xbow,
               (void *) 0);
    device_desc_free(dev_desc);

    xwidget_error_register(conn, xbow_error_handler, soft);

#else
    FIXME("xbow_attach: Fixme: we bypassed attaching xbow error interrupt.\n");
#endif /* LATER */

    /*
     * 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",
            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", busv, port);
#endif
        continue;
    }
#if DEBUG && XBOW_DEBUG
    printk(KERN_INFO "0x%p link %d has a widget\n",
        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 */
}

/*ARGSUSED */
int
xbow_open(devfs_handle_t *devp, int oflag, int otyp, cred_t *credp)
{
    return 0;

}

/*ARGSUSED */
int
xbow_close(devfs_handle_t dev, int oflag, int otyp, cred_t *crp)
{
    return 0;
}

/*ARGSUSED */
int
xbow_map(devfs_handle_t dev, vhandl_t *vt, off_t off, size_t len, uint prot)
{
    devfs_handle_t            vhdl = dev_to_vhdl(dev);
    xbow_soft_t             soft = xbow_soft_get(vhdl);
    int                     error;

    ASSERT(soft);
    len = ctob(btoc(len));
    /* XXX- this ignores the offset!!! */
    error = v_mapphys(vt, (void *) soft->base, len);
    return error;
}

/*ARGSUSED */
int
xbow_unmap(devfs_handle_t dev, vhandl_t *vt)
{
    return 0;
}

/* This contains special-case code for grio. There are plans to make
 * this general sometime in the future, but till then this should
 * be good enough.
 */
xwidgetnum_t
xbow_widget_num_get(devfs_handle_t dev)
{
    devfs_handle_t    tdev;
    char        devname[MAXDEVNAME];
    xwidget_info_t    xwidget_info;
    int        i;

    vertex_to_name(dev, devname, MAXDEVNAME);

    /* If this is a pci controller vertex, traverse up using
     * the ".." links to get to the widget.
     */
    if (strstr(devname, EDGE_LBL_PCI) &&
            strstr(devname, EDGE_LBL_CONTROLLER)) {
        tdev = dev;
        for (i=0; i< 2; i++) {
            if (hwgraph_edge_get(tdev,
                HWGRAPH_EDGELBL_DOTDOT, &tdev) !=
                    GRAPH_SUCCESS)
                return XWIDGET_NONE;
        }

        if ((xwidget_info = xwidget_info_chk(tdev)) != NULL) {
            return (xwidget_info_id_get(xwidget_info));
        } else {
            return XWIDGET_NONE;
        }
    }

    return XWIDGET_NONE;
}

int
xbow_ioctl(devfs_handle_t dev,
       int cmd,
       void *arg,
       int flag,
       struct cred *cr,
       int *rvalp)
{
    devfs_handle_t            vhdl;
    int                     error = 0;

#if defined (DEBUG)
    int                     rc;
    devfs_handle_t            conn;
    struct xwidget_info_s  *xwidget_info;
    xbow_soft_t             xbow_soft;
#endif
    *rvalp = 0;

    vhdl = dev_to_vhdl(dev);
#if defined (DEBUG)
    xbow_soft = xbow_soft_get(vhdl);
    conn = xbow_soft->conn;

    xwidget_info = xwidget_info_get(conn);
    ASSERT_ALWAYS(xwidget_info != NULL);

    rc = xwidget_hwid_is_xswitch(&xwidget_info->w_hwid);
    ASSERT_ALWAYS(rc != 0);
#endif
    switch (cmd) {
#ifdef LATER
    case XBOWIOC_PERF_ENABLE:
    case XBOWIOC_PERF_DISABLE:
    {
        struct xbow_perfarg_t   xbow_perf_en;

        if (!_CAP_CRABLE(cr, CAP_DEVICE_MGT)) {
        error = EPERM;
        break;
        }
        if ((flag & FWRITE) == 0) {
        error = EBADF;
        break;
        }
        if (COPYIN(arg, &xbow_perf_en, sizeof(xbow_perf_en))) {
        error = EFAULT;
        break;
        }
        if (error = xbow_enable_perf_counter(vhdl,
                         xbow_perf_en.link,
                         (cmd == XBOWIOC_PERF_DISABLE) ? 0 : xbow_perf_en.mode,
                         xbow_perf_en.counter)) {
        error = EINVAL;
        break;
        }
        break;
    }
#endif

#ifdef LATER
    case XBOWIOC_PERF_GET:
    {
        xbow_perf_link_t       *xbow_perf_cnt;

        if ((flag & FREAD) == 0) {
        error = EBADF;
        break;
        }
        xbow_perf_cnt = xbow_get_perf_counters(vhdl);
        ASSERT_ALWAYS(xbow_perf_cnt != NULL);

        if (COPYOUT((void *) xbow_perf_cnt, (void *) arg,
            MAX_XBOW_PORTS * sizeof(xbow_perf_link_t))) {
        error = EFAULT;
        break;
        }
        break;
    }
#endif

    case XBOWIOC_LLP_ERROR_ENABLE:
    if ((error = xbow_enable_llp_monitor(vhdl)) != 0)
        error = EINVAL;

    break;

    case XBOWIOC_LLP_ERROR_DISABLE:

    if ((error = xbow_disable_llp_monitor(vhdl)) != 0)
        error = EINVAL;

    break;

#ifdef LATER
    case XBOWIOC_LLP_ERROR_GET:
    {
        xbow_link_status_t     *xbow_llp_status;

        if ((flag & FREAD) == 0) {
        error = EBADF;
        break;
        }
        xbow_llp_status = xbow_get_llp_status(vhdl);
        ASSERT_ALWAYS(xbow_llp_status != NULL);

        if (COPYOUT((void *) xbow_llp_status, (void *) arg,
            MAX_XBOW_PORTS * sizeof(xbow_link_status_t))) {
        error = EFAULT;
        break;
        }
        break;
    }
#endif

#ifdef LATER
    case GIOCSETBW:
    {
        grio_ioctl_info_t info;
        xwidgetnum_t src_widgetnum, dest_widgetnum;

        if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
        error = EFAULT;
        break;
        }
#ifdef GRIO_DEBUG
        printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n",
            info.prev_vhdl, info.next_vhdl, info.reqbw);
#endif /* GRIO_DEBUG */

        src_widgetnum = xbow_widget_num_get(info.prev_vhdl);
        dest_widgetnum = xbow_widget_num_get(info.next_vhdl);

        /* Bandwidth allocation is bi-directional. Since bandwidth
         * reservations have already been done at an earlier stage,
         * we cannot fail here for lack of bandwidth.
         */
        xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum,
            0, info.reqbw);
        xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum,
            0, info.reqbw);

        break;
    }

    case GIOCRELEASEBW:
    {
        grio_ioctl_info_t info;
        xwidgetnum_t src_widgetnum, dest_widgetnum;

        if (!cap_able(CAP_DEVICE_MGT)) {
        error = EPERM;
        break;
        }

        if (COPYIN(arg, &info, sizeof(grio_ioctl_info_t))) {
        error = EFAULT;
        break;
        }
#ifdef GRIO_DEBUG
        printf("xbow:: prev_vhdl: %d next_vhdl: %d reqbw: %lld\n",
            info.prev_vhdl, info.next_vhdl, info.reqbw);
#endif /* GRIO_DEBUG */

        src_widgetnum = xbow_widget_num_get(info.prev_vhdl);
        dest_widgetnum = xbow_widget_num_get(info.next_vhdl);

        /* Bandwidth reservation is bi-directional. Hence, remove
         * bandwidth reservations for both directions.
         */
        xbow_prio_bw_alloc(dev, src_widgetnum, dest_widgetnum,
            info.reqbw, (-1 * info.reqbw));
        xbow_prio_bw_alloc(dev, dest_widgetnum, src_widgetnum,
            info.reqbw, (-1 * info.reqbw));

        break;
    }
#endif

    default:
    break;

    }
    return error;
}

/*
 * 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 {
        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.
 */
devfs_handle_t
xbow_widget_lookup(devfs_handle_t vhdl,
           int widgetnum)
{
    xswitch_info_t          xswitch_info;
    devfs_handle_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.
 */
#ifdef LATER
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);
}
#endif    /* LATER */

/*
 * 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%x\n", (n), (v))
#define    XEM_ADD_VAR(v)        XEM_ADD_NVAR(#v,(v))
#define XEM_ADD_IOEF(n)     if (IOERROR_FIELDVALID(ioe,n))            \
                    XEM_ADD_NVAR("ioe." #n,            \
                         IOERROR_GETVALUE(ioe,n))

#ifdef LATER
static void
xem_add_ioe(ioerror_t *ioe)
{
    XEM_ADD_IOEF(errortype);
    XEM_ADD_IOEF(widgetnum);
    XEM_ADD_IOEF(widgetdev);
    XEM_ADD_IOEF(srccpu);
    XEM_ADD_IOEF(srcnode);
    XEM_ADD_IOEF(errnode);
    XEM_ADD_IOEF(sysioaddr);
    XEM_ADD_IOEF(xtalkaddr);
    XEM_ADD_IOEF(busspace);
    XEM_ADD_IOEF(busaddr);
    XEM_ADD_IOEF(vaddr);
    XEM_ADD_IOEF(memaddr);
    XEM_ADD_IOEF(epc);
    XEM_ADD_IOEF(ef);
}

#define XEM_ADD_IOE()    (xem_add_ioe(ioe))
#endif    /* LATER */

int                     xbow_xmit_retry_errors = 0;

int
xbow_xmit_retry_error(xbow_soft_t soft,
              int port)
{
    xswitch_info_t          info;
    devfs_handle_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);

    /* If this thing is not a Bridge,
     * do not activate the WAR, and
     * tell our caller we do not need
     * to be called again.
     */
    if ((part != BRIDGE_WIDGET_PART_NUM) ||
    (mfgr != BRIDGE_WIDGET_MFGR_NUM)) {
        /* FIXME: add Xbridge to the WAR.
         * Shouldn't hurt anything.  Later need to
         * check if we can remove this.
                 */
            if ((part != XBRIDGE_WIDGET_PART_NUM) ||
            (mfgr != XBRIDGE_WIDGET_MFGR_NUM))
            return 0;
    }

    /* count how many times we
     * have picked up after
     * LLP Transmit problems.
     */
    xbow_xmit_retry_errors++;

    /* rewrite the control register
     * to fix things up.
     */
    wid->w_control = wid->w_control;
    wid->w_control;

    return 1;
}

/*
 * xbow_errintr_handler will be called if the xbow
 * sends an interrupt request to report an error.
 */

#ifdef LATER
static void
xbow_errintr_handler(intr_arg_t arg)
{
    ioerror_t               ioe[1];
    xbow_soft_t             soft = (xbow_soft_t) 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;
    uint64_t                 wid_err_addr;

    int                     fatal = 0;
    int                     dump_ioe = 0;

    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) {
            devfs_handle_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);

#ifdef    LATER
            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");
#endif    /* LATER */
            {
            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 (dump_ioe) {
                XEM_ADD_IOE();
                dump_ioe = 0;
            }
#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);
    PRINT_PANIC("XIO Bus Error");
    }
}
#endif    /* LATER */

/*
 * 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.
 */

#ifdef LATER
static int
xbow_error_handler(
              void *einfo,
              int error_code,
              ioerror_mode_t mode,
              ioerror_t *ioerror)
{
    int                     retval = IOERROR_WIDGETLEVEL;

    xbow_soft_t             soft = (xbow_soft_t) einfo;
    int                     port;
    devfs_handle_t            conn;
    devfs_handle_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;
    uint64_t                 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

    port = IOERROR_GETVALUE(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) {
        PRINT_ALERT("DMA error blamed on Crossbow at %s\n"
            "\tbut Crosbow never initiates DMA!",
            soft->name);
    }
    if (error_code & IOECODE_PIO) {
        PRINT_ALERt("PIO Error on XIO Bus %s\n"
            "\tattempting to access XIO controller\n"
            "\twith offset 0x%X",
            soft->name,
            IOERROR_GETVALUE(ioerror, xtalkaddr));
    }
    /* 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) {
        PRINT_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) {
        PRINT_ALERT("PIO Error on XIO Bus %s\n"
            "\tattempting to access XIO port %d\n"
            "\t(which Crossbow does not support)"
            "\twith offset 0x%X",
            soft->name, port,
            IOERROR_GETVALUE(ioerror, xtalkaddr));
    }
#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.
     */
    if (!(link_aux_status & XB_AUX_STAT_PRESENT)) {
    /* nobody connected. */
    if (mode == MODE_DEVPROBE)
        return IOERROR_HANDLED;

    if (error_code & IOECODE_DMA) {
        PRINT_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) {
        PRINT_ALERT("PIO Error on XIO Bus %s\n"
            "\tattempting to access XIO port %d\n"
            "\t(which has no device connected)"
            "\twith offset 0x%X",
            soft->name, port,
            IOERROR_GETVALUE(ioerror, xtalkaddr));
    }
#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)) {
    /* nobody connected. */
    if (mode == MODE_DEVPROBE)
        return IOERROR_HANDLED;

    PRINT_ALERT("%s%sError on XIO Bus %s port %d",
        (error_code & IOECODE_DMA) ? "DMA " : "",
        (error_code & IOECODE_PIO) ? "PIO " : "",
        soft->name, port);

    if ((error_code & IOECODE_PIO) &&
        (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
        printk("\tAccess attempted to offset 0x%X\n",
            IOERROR_GETVALUE(ioerror, xtalkaddr));
    }
    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) {
    retval = IOERROR_PANIC;

    PRINT_ALERT("%s%sError on XIO Bus %s port %d",
        (error_code & IOECODE_DMA) ? "DMA " : "",
        (error_code & IOECODE_PIO) ? "PIO " : "",
        soft->name, port);

    if ((error_code & IOECODE_PIO) &&
        (IOERROR_FIELDVALID(ioerror, xtalkaddr))) {
        printk("\tAccess attempted to offset 0x%X\n",
            IOERROR_GETVALUE(ioerror, xtalkaddr));
    }
    }

#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;
}

#endif    /* LATER */

void
xbow_update_perf_counters(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
    xbow_perf_link_t       *xbow_plink = xbow_soft->xbow_perflink;
    xbow_perfcount_t        perf_reg;
    unsigned long           s;
    int                     link, i;

    for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) {
    if (xbow_perf->xp_mode == XBOW_MONITOR_NONE)
        continue;

    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);

    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;

    link = perf_reg.xb_perf.link_select;

    (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] +=
        ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK);
    xbow_perf->xp_current = perf_reg.xb_perf.count;

    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
    }
    /* Do port /mode multiplexing here */

#ifdef LATER
    (void) timeout(xbow_update_perf_counters,
           (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);
#endif

}

xbow_perf_link_t       *
xbow_get_perf_counters(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    xbow_perf_link_t       *xbow_perf_link = xbow_soft->xbow_perflink;

    return xbow_perf_link;
}

int
xbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    xbow_perf_t            *xbow_perf = xbow_soft->xbow_perfcnt;
    xbow_linkctrl_t         xbow_link_ctrl;
    xbow_t                 *xbow = xbow_soft->base;
    xbow_perfcount_t        perf_reg;
    unsigned long           s;
    int                     i;

    link -= BASE_XBOW_PORT;
    if ((link < 0) || (link >= MAX_XBOW_PORTS))
    return -1;

    if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK))
    return -1;

    if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS))
    return -1;

    s = mutex_spinlock(&xbow_soft->xbow_perf_lock);

    if ((xbow_perf + counter)->xp_mode && mode) {
    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
    return -1;
    }
    for (i = 0; i < XBOW_PERF_COUNTERS; i++) {
    if (i == counter)
        continue;
    if (((xbow_perf + i)->xp_link == link) &&
        ((xbow_perf + i)->xp_mode)) {
        mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);
        return -1;
    }
    }
    xbow_perf += counter;

    xbow_perf->xp_curlink = xbow_perf->xp_link = link;
    xbow_perf->xp_curmode = xbow_perf->xp_mode = mode;

    xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control;
    xbow_link_ctrl.xb_linkcontrol.perf_mode = mode;
    xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword;

    perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg;
    perf_reg.xb_perf.link_select = link;
    *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val;
    xbow_perf->xp_current = perf_reg.xb_perf.count;

#ifdef LATER
    (void) timeout(xbow_update_perf_counters,
           (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);
#endif

    mutex_spinunlock(&xbow_soft->xbow_perf_lock, s);

    return 0;
}

xbow_link_status_t     *
xbow_get_llp_status(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;

    return xbow_llp_status;
}

void
xbow_update_llp_status(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    xbow_link_status_t     *xbow_llp_status = xbow_soft->xbow_link_status;
    xbow_t                 *xbow;
    xbwX_stat_t             lnk_sts;
    xbow_aux_link_status_t  aux_sts;
    int                     link;
    devfs_handle_t        xwidget_vhdl;
    char           *xwidget_name;    

    xbow = (xbow_t *) xbow_soft->base;
    for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) {
    /* Get the widget name corresponding the current link.
     * Note : 0 <= link < MAX_XBOW_PORTS(8).
     *       BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10)
     */
    xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT);
    xwidget_name = xwidget_name_get(xwidget_vhdl);
    aux_sts.aux_linkstatus
        = xbow->xb_link_raw[link].link_aux_status;
    lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr;

    if (lnk_sts.link_alive == 0)
        continue;

    xbow_llp_status->rx_err_count +=
        aux_sts.xb_aux_linkstatus.rx_err_cnt;

    xbow_llp_status->tx_retry_count +=
        aux_sts.xb_aux_linkstatus.tx_retry_cnt;

    if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {
#ifdef    LATER
        PRINT_WARNING("link %d[%s]: bad status 0x%x\n",
            link, xwidget_name, lnk_sts.linkstatus);
#endif
    }
    }
#ifdef LATER
    if (xbow_soft->link_monitor)
    (void) timeout(xbow_update_llp_status,
               (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);
#endif
}

int
xbow_disable_llp_monitor(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);
    int                     port;

    for (port = 0; port < MAX_XBOW_PORTS; port++) {
    xbow_soft->xbow_link_status[port].rx_err_count = 0;
    xbow_soft->xbow_link_status[port].tx_retry_count = 0;
    }

    xbow_soft->link_monitor = 0;
    return 0;
}

int
xbow_enable_llp_monitor(devfs_handle_t vhdl)
{
    xbow_soft_t             xbow_soft = xbow_soft_get(vhdl);

#ifdef LATER
    (void) timeout(xbow_update_llp_status,
           (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);
#endif
    xbow_soft->link_monitor = 1;
    return 0;
}


int
xbow_reset_link(devfs_handle_t xconn_vhdl)
{
    xwidget_info_t          widget_info;
    xwidgetnum_t            port;
    xbow_t                 *xbow;
    xbowreg_t               ctrl;
    xbwX_stat_t             stat;
    unsigned                itick;
    unsigned                dtick;
    static int              ticks_per_ms = 0;

    if (!ticks_per_ms) {
    itick = get_timestamp();
    us_delay(1000);
    ticks_per_ms = get_timestamp() - itick;
    }
    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
    {
    devfs_handle_t            xbow_vhdl;
    xbow_soft_t             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 = get_timestamp();
    while (1) {
    stat.linkstatus = xbow->xb_link(port).link_status;
    if (stat.link_alive)
        break;
    dtick = get_timestamp() - itick;
    if (dtick > ticks_per_ms) {
        return -1;            /* never came out of reset */
    }
    DELAY(2);            /* don't beat on link_status */
    }
    xbow->xb_link(port).link_control = ctrl;
    return 0;
}

/*
 * Dump xbow registers.
 * input parameter is either a pointer to
 * the xbow chip or the vertex handle for
 * an xbow vertex.
 */
void
idbg_xbowregs(int64_t regs)
{
    xbow_t                 *xbow;
    int                     i;
    xb_linkregs_t          *link;

#ifdef LATER
    if (dev_is_vertex((devfs_handle_t) regs)) {
    devfs_handle_t            vhdl = (devfs_handle_t) regs;
    xbow_soft_t             soft = xbow_soft_get(vhdl);

    xbow = soft->base;
    } else
#endif
    {
    xbow = (xbow_t *) regs;
    }

#ifdef LATER
    qprintf("Printing xbow registers starting at 0x%x\n", xbow);
    qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n",
        xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper,
        xbow->xb_wid_err_lower, xbow->xb_wid_control,
        xbow->xb_wid_req_timeout);
    qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n",
        xbow->xb_wid_int_upper, xbow->xb_wid_int_lower,
        xbow->xb_wid_err_cmdword, xbow->xb_wid_llp,
        xbow->xb_wid_arb_reload);
#endif

    for (i = 8; i <= 0xf; i++) {
    link = &xbow->xb_link(i);
#ifdef LATER
    qprintf("Link %d registers\n", i);
    qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n",
        link->link_control, link->link_status,
        link->link_arb_upper, link->link_arb_lower,
        link->link_aux_status);
#endif
    }
}


#define XBOW_ARB_RELOAD_TICKS        25
                    /* granularity: 4 MB/s, max: 124 MB/s */
#define GRANULARITY            ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)

#define XBOW_BYTES_TO_GBR(BYTES_per_s)    (int) (BYTES_per_s / GRANULARITY)

#define XBOW_GBR_TO_BYTES(cnt)        (bandwidth_t) ((cnt) * GRANULARITY)

#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec)    \
            ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)

#define XBOW_ARB_GBR_MAX        31

#define ABS(x)                ((x > 0) ? (x) : (-1 * x))
                    /* absolute value */

int
xbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec)
{
    int                     gbr_granted;
    int                     new_total_gbr;
    int                     change_gbr;
    bandwidth_t             new_total_bw;

#ifdef GRIO_DEBUG
    printf("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n",
        old_bytes_per_sec, bytes_per_sec);
#endif    /* GRIO_DEBUG */

    gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)),
            old_bytes_per_sec);
    new_total_bw = old_bytes_per_sec + bytes_per_sec;
    new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)),
            new_total_bw);

    change_gbr = new_total_gbr - gbr_granted;

#ifdef GRIO_DEBUG
    printf("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n",
        gbr_granted, new_total_gbr, change_gbr);
#endif    /* GRIO_DEBUG */

    return (change_gbr);
}

/* Conversion from GBR to bytes */
bandwidth_t
xbow_gbr_to_bytes(int gbr)
{
    return (XBOW_GBR_TO_BYTES(gbr));
}

/* Given the vhdl for the desired xbow, the src and dest. widget ids
 * and the req_bw value, this xbow driver entry point accesses the
 * xbow registers and allocates the desired bandwidth if available.
 *
 * If bandwidth allocation is successful, return success else return failure.
 */
int
xbow_prio_bw_alloc(devfs_handle_t vhdl,
        xwidgetnum_t src_wid,
        xwidgetnum_t dest_wid,
        unsigned long long old_alloc_bw,
        unsigned long long req_bw)
{
    xbow_soft_t             soft = xbow_soft_get(vhdl);
    volatile xbowreg_t     *xreg;
    xbowreg_t               mask;
    unsigned long           s;
    int                     error = 0;
    bandwidth_t             old_bw_BYTES, req_bw_BYTES;
    xbowreg_t               old_xreg;
    int                     old_bw_GBR, req_bw_GBR, new_bw_GBR;

#ifdef GRIO_DEBUG
    printf("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n",
        (int) vhdl, (int) src_wid, (int) dest_wid, req_bw);
#endif

    ASSERT(XBOW_WIDGET_IS_VALID(src_wid));
    ASSERT(XBOW_WIDGET_IS_VALID(dest_wid));

    s = mutex_spinlock(&soft->xbow_bw_alloc_lock);

    /* Get pointer to the correct register */
    xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid);

    /* Get mask for GBR count value */
    mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid);

    req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw);
    req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR)))
        : xbow_gbr_to_bytes(req_bw_GBR);

#ifdef GRIO_DEBUG
    printf("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n",
        req_bw, req_bw_BYTES, req_bw_GBR);
#endif    /* GRIO_DEBUG */

    old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS];
    old_xreg = *xreg;
    old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));

#ifdef GRIO_DEBUG
    ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR);

    printf("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR);

    printf("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n",
        req_bw_BYTES, old_bw_BYTES,
        soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]);
       
#endif                /* GRIO_DEBUG */

    /* Accept the request only if we don't exceed the destination
     * port HIWATER_MARK *AND* the max. link GBR arbitration count
     */
    if (((old_bw_BYTES + req_bw_BYTES) <=
        soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) &&
        (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) {

    new_bw_GBR = (old_bw_GBR + req_bw_GBR);

    /* Set this in the xbow link register */
    *xreg = (old_xreg & ~mask) | \
        (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask);

    soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] =
            xbow_gbr_to_bytes(new_bw_GBR);
    } else {
    error = 1;
    }

    mutex_spinunlock(&soft->xbow_bw_alloc_lock, s);

    return (error);
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0344 ]--