!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:     io.c (35.28 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/config.h>
#include <linux/slab.h>
#include <asm/sn/types.h>
#include <asm/sn/sgi.h>
#include <asm/sn/iobus.h>
#include <asm/sn/iograph.h>
#include <asm/param.h>
#include <asm/sn/pio.h>
#include <asm/sn/xtalk/xwidget.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/addrs.h>
#include <asm/sn/invent.h>
#include <asm/sn/hcl.h>
#include <asm/sn/hcl_util.h>
#include <asm/sn/agent.h>
#include <asm/sn/intr.h>
#include <asm/sn/xtalk/xtalkaddrs.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/io.h>
#include <asm/sn/sn_cpuid.h>

extern xtalk_provider_t hub_provider;

/*
 * Perform any initializations needed to support hub-based I/O.
 * Called once during startup.
 */
void
hubio_init(void)
{
#ifdef    LATER
    /* This isn't needed unless we port the entire sio driver ... */
        extern void early_brl1_port_init( void );
    early_brl1_port_init();
#endif
}

/* 
 * 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(devfs_handle_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);

    mutex_spinlock_init(&hubinfo->h_bwlock);
/*
 * If this lock can be acquired from interrupts or bh's, add SV_INTS or SV_BHS,
 * respectively, to the flags here.
 */
    sv_init(&hubinfo->h_bwwait, &hubinfo->h_bwlock, SV_ORDER_FIFO | SV_MON_SPIN); 
}

/* 
 * 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(devfs_handle_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);
    devfs_handle_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;
    unsigned long s;

    /* 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)
        return(hubinfo_swin_piomap_get(hubinfo, (int)widget));

    /* 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;
    s = mutex_spinlock(&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++;
            mutex_spinunlock(&hubinfo->h_bwlock, s);
            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;
            }

            sv_wait(&hubinfo->h_bwwait, 0, 0);
            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;
    bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index);
    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:
    mutex_spinunlock(&hubinfo->h_bwlock, s);
    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)
{
    devfs_handle_t hubv;
    hubinfo_t hubinfo;
    nasid_t nasid;
    unsigned long s;

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

    s = mutex_spinlock(&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;

        (void)sv_signal(&hubinfo->h_bwwait);
    }

    mutex_spinunlock(&hubinfo->h_bwlock, s);
}

/*
 * 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(    devfs_handle_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);
    devfs_handle_t hubv = xwidget_info_master_get(widget_info);
    hub_piomap_t hub_piomap;
    hubinfo_t hubinfo;

    hubinfo_get(hubv, &hubinfo);

    if (xtalk_addr + byte_count <= SWIN_SIZE) {
        hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget);
        return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count));
    } else
        return(0);
}


/* DMA MANAGEMENT */
/* Mapping from crosstalk space to system physical space */

/* 
 * There's not really very much to do here, since crosstalk maps
 * directly to system physical space.  It's quite possible that this
 * DMA layer will be bypassed in performance kernels.
 */


/* ARGSUSED */
static void
hub_dma_init(devfs_handle_t hubv)
{
}


/*
 * 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(    devfs_handle_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);
    devfs_handle_t hubv = xwidget_info_master_get(widget_info);

    dmamap = kern_malloc(sizeof(struct hub_dmamap_s));
    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;
    kern_free(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 */
{
    devfs_handle_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)) {
        vhdl = dmamap->hdma_xtalk_info.xd_dev;
#if defined(SUPPORT_PRINTING_V_FORMAT)
        PRINT_WARNING("%v: hub_dmamap_addr re-uses dmamap.\n",vhdl);
#else
        PRINT_WARNING("0x%x: hub_dmamap_addr re-uses dmamap.\n", vhdl);
#endif
        }
    } else {
        dmamap->hdma_flags |= HUB_DMAMAP_USED;
    }

    /* There isn't actually any DMA mapping hardware on the hub. */
    return(paddr);
}

/*
 * Establish a DMA mapping using the resources allocated in a previous dmamap_alloc.
 * Return an appropriate crosstalk address list that maps to the specified physical 
 * address list.
 */
/* ARGSUSED */
alenlist_t
hub_dmamap_list(hub_dmamap_t hub_dmamap,    /* use these mapping resources */
        alenlist_t palenlist,        /* map this area of memory */
        unsigned flags)
{
    devfs_handle_t vhdl;

    ASSERT(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_VALID);

    if (hub_dmamap->hdma_flags & HUB_DMAMAP_USED) {
        /* If the map is FIXED, re-use is OK. */
        if (!(hub_dmamap->hdma_flags & HUB_DMAMAP_IS_FIXED)) {
        vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
#if defined(SUPPORT_PRINTING_V_FORMAT)
        PRINT_WARNING("%v: hub_dmamap_list re-uses dmamap\n",vhdl);
#else
        PRINT_WARNING("0x%x: hub_dmamap_list re-uses dmamap\n", vhdl);
#endif
        }
    } else {
        hub_dmamap->hdma_flags |= HUB_DMAMAP_USED;
    }

    /* There isn't actually any DMA mapping hardware on the hub.  */
    return(palenlist);
}

/*
 * Driver indicates that it has completed whatever DMA it may have started
 * after an earlier dmamap_addr or dmamap_list call.
 */
void
hub_dmamap_done(hub_dmamap_t hub_dmamap)    /* done with these mapping resources */
{
    devfs_handle_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)) {
        vhdl = hub_dmamap->hdma_xtalk_info.xd_dev;
#if defined(SUPPORT_PRINTING_V_FORMAT)
        PRINT_WARNING("%v: hub_dmamap_done already done with dmamap\n",vhdl);
#else
        PRINT_WARNING("0x%x: hub_dmamap_done already done with dmamap\n", vhdl);
#endif
        }
    }
}

/*
 * Translate a single system physical address into a crosstalk address.
 */
/* ARGSUSED */
iopaddr_t
hub_dmatrans_addr(    devfs_handle_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 */
{
    /* no translation needed */
    return(paddr);
}

/*
 * Translate a list of IP27 addresses and lengths into a list of crosstalk 
 * addresses and lengths.  No actual hardware mapping takes place; the hub 
 * has no DMA mapping registers -- crosstalk addresses map directly.
 */
/* ARGSUSED */
alenlist_t
hub_dmatrans_list(    devfs_handle_t dev,    /* translate for this device */
            device_desc_t dev_desc,    /* device descriptor */
            alenlist_t palenlist,    /* system address/length list */
            unsigned flags)        /* defined in dma.h */
{
    /* no translation needed */
    return(palenlist);
}

/*ARGSUSED*/
void
hub_dmamap_drain(    hub_dmamap_t map)
{
    /* XXX- flush caches, if cache coherency WAR is needed */
}

/*ARGSUSED*/
void
hub_dmaaddr_drain(    devfs_handle_t vhdl,
            paddr_t addr,
            size_t bytes)
{
    /* XXX- flush caches, if cache coherency WAR is needed */
}

/*ARGSUSED*/
void
hub_dmalist_drain(    devfs_handle_t vhdl,
            alenlist_t list)
{
    /* XXX- flush caches, if cache coherency WAR is needed */
}



/* INTERRUPT MANAGEMENT */

/* ARGSUSED */
static void
hub_intr_init(devfs_handle_t hubv)
{
}

/*
 * hub_device_desc_update
 *    Update the passed in device descriptor with the actual the
 *     target cpu number and interrupt priority level.
 *    NOTE : These might be the same as the ones passed in thru
 *    the descriptor.
 */
static void
hub_device_desc_update(device_desc_t     dev_desc, 
               ilvl_t         intr_swlevel,
               cpuid_t        cpu)
{
    char    cpuname[40];
    
    /* Store the interrupt priority level in the device descriptor */
    device_desc_intr_swlevel_set(dev_desc, intr_swlevel);

    /* Convert the cpuid to the vertex handle in the hwgraph and
     * save it in the device descriptor.
     */
    sprintf(cpuname,"/hw/cpunum/%ld",cpu);
    device_desc_intr_target_set(dev_desc, 
                    hwgraph_path_to_dev(cpuname));
}

int allocate_my_bit = INTRCONNECT_ANYBIT;

/*
 * Allocate resources required for an interrupt as specified in dev_desc.
 * Returns a hub interrupt handle on success, or 0 on failure.
 */
static hub_intr_t
do_hub_intr_alloc(devfs_handle_t dev,        /* which crosstalk device */
          device_desc_t dev_desc,    /* device descriptor */
          devfs_handle_t owner_dev,    /* owner of this interrupt, if known */
          int uncond_nothread)        /* unconditionally non-threaded */
{
    cpuid_t cpu = (cpuid_t)0;            /* cpu to receive interrupt */
        int cpupicked = 0;
    int bit;            /* interrupt vector */
    /*REFERENCED*/
    int intr_resflags = 0;
    hub_intr_t intr_hdl;
    cnodeid_t nodeid;        /* node to receive interrupt */
    /*REFERENCED*/
    nasid_t nasid;            /* nasid to receive interrupt */
    struct xtalk_intr_s *xtalk_info;
    iopaddr_t xtalk_addr;        /* xtalk addr on hub to set intr */
    xwidget_info_t xwidget_info;    /* standard crosstalk widget info handle */
    char *intr_name = NULL;
    ilvl_t intr_swlevel;
    extern int default_intr_pri;
#ifdef CONFIG_IA64_SGI_SN1 
    extern void synergy_intr_alloc(int, int);
#endif
    
    /*
     * If caller didn't explicily specify a device descriptor, see if there's
     * a default descriptor associated with the device.
     */
    if (!dev_desc) 
        dev_desc = device_desc_default_get(dev);

    if (dev_desc) {
        intr_name = device_desc_intr_name_get(dev_desc);
        intr_swlevel = device_desc_intr_swlevel_get(dev_desc);
        if (dev_desc->flags & D_INTR_ISERR) {
            intr_resflags = II_ERRORINT;
        } else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) {
            intr_resflags = II_THREADED;
        } else {
            /* Neither an error nor a thread. */
            intr_resflags = 0;
        }
    } else {
        intr_swlevel = default_intr_pri;
        if (!uncond_nothread)
            intr_resflags = II_THREADED;
    }

    /* XXX - Need to determine if the interrupt should be threaded. */

    /* If the cpu has not been picked already then choose a candidate 
     * interrupt target and reserve the interrupt bit 
     */
#if defined(NEW_INTERRUPTS)
    if (!cpupicked) {
        cpu = intr_heuristic(dev,dev_desc,allocate_my_bit,
                     intr_resflags,owner_dev,
                     intr_name,&bit);
    }
#endif

    /* At this point we SHOULD have a valid cpu */
    if (cpu == CPU_NONE) {
#if defined(SUPPORT_PRINTING_V_FORMAT)
        PRINT_WARNING("%v hub_intr_alloc could not allocate interrupt\n",
            owner_dev);
#else
        PRINT_WARNING("0x%x hub_intr_alloc could not allocate interrupt\n",
            owner_dev);
#endif
        return(0);

    }

    /* If the cpu has been picked already (due to the bridge data 
     * corruption bug) then try to reserve an interrupt bit .
     */
#if defined(NEW_INTERRUPTS)
    if (cpupicked) {
        bit = intr_reserve_level(cpu, allocate_my_bit, 
                     intr_resflags, 
                     owner_dev, intr_name);
        if (bit < 0) {
#if defined(SUPPORT_PRINTING_V_FORMAT)
            PRINT_WARNING("Could not reserve an interrupt bit for cpu "
                " %d and dev %v\n",
                cpu,owner_dev);
#else
            PRINT_WARNING("Could not reserve an interrupt bit for cpu "
                " %d and dev 0x%x\n",
                cpu, owner_dev);
#endif
                
            return(0);
        }
    }
#endif    /* NEW_INTERRUPTS */

    nodeid = cpuid_to_cnodeid(cpu);
    nasid = cpuid_to_nasid(cpu);
    xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu)));

    /*
     * Allocate an interrupt handle, and fill it in.  There are two
     * pieces to an interrupt handle: the piece needed by generic
     * xtalk code which is used by crosstalk device drivers, and
     * the piece needed by low-level IP27 hardware code.
     */
    intr_hdl = kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid);
    ASSERT_ALWAYS(intr_hdl);

    /* 
     * Fill in xtalk information for generic xtalk interfaces that
     * operate on xtalk_intr_hdl's.
     */
    xtalk_info = &intr_hdl->i_xtalk_info;
    xtalk_info->xi_dev = dev;
    xtalk_info->xi_vector = bit;
    xtalk_info->xi_addr = xtalk_addr;

    /*
     * Regardless of which CPU we ultimately interrupt, a given crosstalk
     * widget always handles interrupts (and PIO and DMA) through its 
     * designated "master" crosstalk provider.
     */
    xwidget_info = xwidget_info_get(dev);
    if (xwidget_info)
        xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info);

    /* Fill in low level hub information for hub_* interrupt interface */
    intr_hdl->i_swlevel = intr_swlevel;
    intr_hdl->i_cpuid = cpu;
    intr_hdl->i_bit = bit;
    intr_hdl->i_flags = HUB_INTR_IS_ALLOCED;

    /* Store the actual interrupt priority level & interrupt target
     * cpu back in the device descriptor.
     */
    hub_device_desc_update(dev_desc, intr_swlevel, cpu);
#ifdef CONFIG_IA64_SGI_SN1
    synergy_intr_alloc((int)bit, (int)cpu);
#endif
    return(intr_hdl);
}

/*
 * Allocate resources required for an interrupt as specified in dev_desc.
 * Returns a hub interrupt handle on success, or 0 on failure.
 */
hub_intr_t
hub_intr_alloc(    devfs_handle_t dev,        /* which crosstalk device */
        device_desc_t dev_desc,        /* device descriptor */
        devfs_handle_t owner_dev)        /* owner of this interrupt, if known */
{
    return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 0));
}

/*
 * Allocate resources required for an interrupt as specified in dev_desc.
 * Uncondtionally request non-threaded, regardless of what the device
 * descriptor might say.
 * Returns a hub interrupt handle on success, or 0 on failure.
 */
hub_intr_t
hub_intr_alloc_nothd(devfs_handle_t dev,        /* which crosstalk device */
        device_desc_t dev_desc,        /* device descriptor */
        devfs_handle_t owner_dev)        /* owner of this interrupt, if known */
{
    return(do_hub_intr_alloc(dev, dev_desc, owner_dev, 1));
}

/*
 * Free resources consumed by intr_alloc.
 */
void
hub_intr_free(hub_intr_t intr_hdl)
{
    cpuid_t cpu = intr_hdl->i_cpuid;
    int bit = intr_hdl->i_bit;
    xtalk_intr_t xtalk_info;

    if (intr_hdl->i_flags & HUB_INTR_IS_CONNECTED) {
        /* Setting the following fields in the xtalk interrupt info
          * clears the interrupt target register in the xtalk user
          */
        xtalk_info = &intr_hdl->i_xtalk_info;
        xtalk_info->xi_dev = NODEV;
        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);

#if defined(NEW_INTERRUPTS)
    intr_unreserve_level(cpu, bit);
#endif
}


/*
 * Associate resources allocated with a previous hub_intr_alloc call with the
 * described handler, arg, name, etc.
 */
/*ARGSUSED*/
int
hub_intr_connect(    hub_intr_t intr_hdl,        /* xtalk intr resource handle */
            intr_func_t intr_func,        /* xtalk intr handler */
            void *intr_arg,            /* arg to intr handler */
            xtalk_intr_setfunc_t setfunc,    /* func to set intr hw */
            void *setfunc_arg,        /* arg to setfunc */
            void *thread)            /* intr thread to use */
{
    int rv;
    cpuid_t cpu = intr_hdl->i_cpuid;
    int bit = intr_hdl->i_bit;
#ifdef CONFIG_IA64_SGI_SN1
    extern int synergy_intr_connect(int, int);
#endif

    ASSERT(intr_hdl->i_flags & HUB_INTR_IS_ALLOCED);

#if defined(NEW_INTERRUPTS)
    rv = intr_connect_level(cpu, bit, intr_hdl->i_swlevel, 
                    intr_func, intr_arg, NULL);
    if (rv < 0)
        return(rv);

#endif
    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;
#ifdef CONFIG_IA64_SGI_SN1
    return(synergy_intr_connect((int)bit, (int)cpu));
#endif
}


/*
 * 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);

#if defined(NEW_INTERRUPTS)
    rv = intr_disconnect_level(cpu, bit);
    ASSERT(rv == 0);
#endif

    intr_hdl->i_flags &= ~HUB_INTR_IS_CONNECTED;
}


/*
 * Return a hwgraph vertex that represents the CPU currently
 * targeted by an interrupt.
 */
devfs_handle_t
hub_intr_cpu_get(hub_intr_t intr_hdl)
{
    cpuid_t cpuid = intr_hdl->i_cpuid;
    ASSERT(cpuid != CPU_NONE);

    return(cpuid_to_vertex(cpuid));
}



/* CONFIGURATION MANAGEMENT */

/*
 * Perform initializations that allow this hub to start crosstalk support.
 */
void
hub_provider_startup(devfs_handle_t hubv)
{
    hub_pio_init(hubv);
    hub_dma_init(hubv);
    hub_intr_init(hubv);
}

/*
 * Shutdown crosstalk support from a hub.
 */
void
hub_provider_shutdown(devfs_handle_t hub)
{
    /* TBD */
    xtalk_provider_unregister(hub);
}

/*
 * Check that an address is in teh 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 (((__psunsigned_t)addr >= RAW_NODE_SWIN_BASE(nasid, 0)) &&
        ((__psunsigned_t)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((__psunsigned_t)addra) ==
        WIDGETID_GET((__psunsigned_t)addrb))
        return 1;

    return 0;
}


/*
 * Determine whether two PCI addresses actually refer to the same device.
 * This only works if both addresses are in small windows.  It's used to
 * determine whether prom addresses refer to particular PCI devices.
 */
/*    
 * XXX - This won't work as written if we ever have more than two nodes
 * on a crossbow.  In that case, we'll need an array or partners.
 */
int
hub_check_pci_equiv(void *addra, void *addrb)
{
    nasid_t nasida, nasidb;

    /*
     * This is for a permanent workaround that causes us to use a
     * big window in place of small window 0.
     */
    if (!hub_check_window_equiv(addra, addrb))
        return 0;

    /* If the offsets aren't the same, forget it. */
    if (SWIN_WIDGETADDR((__psunsigned_t)addra) !=
        (SWIN_WIDGETADDR((__psunsigned_t)addrb)))
        return 0;

    /* Now, check the nasids */
    nasida = NASID_GET(addra);
    nasidb = NASID_GET(addrb);

    ASSERT(NASID_TO_COMPACT_NODEID(nasida) != INVALID_NASID);
    ASSERT(NASID_TO_COMPACT_NODEID(nasidb) != INVALID_NASID);

    /*
     * Either the NASIDs must be the same or they must be crossbow
     * partners (on the same crossbow).
     */
    return (check_nasid_equiv(nasida, nasidb));
}

/*
 * hub_setup_prb(nasid, prbnum, credits, conveyor)
 *
 *     Put a PRB into fire-and-forget mode if conveyor isn't set.  Otehrwise,
 *     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;
#ifdef LATER
    extern int force_fire_and_forget;
    extern volatile int ignore_conveyor_override;

    if (force_fire_and_forget && !ignore_conveyor_override)
        if (conveyor == HUB_PIO_CONVEYOR)
        conveyor = HUB_PIO_FIRE_N_FORGET;
#endif

    /*
     * 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;
    int cons_lock = 0;

    ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID);
    if (nasid == get_console_nasid()) {
        PUTBUF_LOCK(s);    
        cons_lock = 1;
    }

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

    if (cons_lock)
        PUTBUF_UNLOCK(s);
}
/* 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;
}
/* Interface to allow special drivers to set hub specific
 * device flags.
 * Return 0 on failure , 1 on success
 */
int
hub_device_flags_set(devfs_handle_t    widget_vhdl,
             hub_widget_flags_t    flags)
{
    xwidget_info_t        widget_info = xwidget_info_get(widget_vhdl);
    xwidgetnum_t        widget_num  = xwidget_info_id_get(widget_info);
    devfs_handle_t        hub_vhdl    = xwidget_info_master_get(widget_info);
    hubinfo_t        hub_info = 0;
    nasid_t            nasid;
    unsigned long        s;
    int            rv;

    /* Use the nasid from the hub info hanging off the hub vertex
     * and widget number from the widget vertex
     */
    hubinfo_get(hub_vhdl, &hub_info);
    /* Being over cautious by grabbing a lock */
    s     = mutex_spinlock(&hub_info->h_bwlock);
    nasid     = hub_info->h_nasid;
    rv     = hub_widget_flags_set(nasid,widget_num,flags);
    mutex_spinunlock(&hub_info->h_bwlock, s);

    return rv;
}

#if ((defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)) && defined(BRINGUP))
/* BRINGUP:  This ought to be useful for IP27 too but, for now,
 * make it SN1 only because `ii_ixtt_u_t' is not in IP27/hubio.h
 * (or anywhere else :-).
 */
int
hubii_ixtt_set(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt)
{
    xwidget_info_t        widget_info = xwidget_info_get(widget_vhdl);
    devfs_handle_t        hub_vhdl    = xwidget_info_master_get(widget_info);
    hubinfo_t        hub_info = 0;
    nasid_t            nasid;
    unsigned long            s;

    /* Use the nasid from the hub info hanging off the hub vertex
     * and widget number from the widget vertex
     */
    hubinfo_get(hub_vhdl, &hub_info);
    /* Being over cautious by grabbing a lock */
    s     = mutex_spinlock(&hub_info->h_bwlock);
    nasid     = hub_info->h_nasid;

    REMOTE_HUB_S(nasid, IIO_IXTT, ixtt->ii_ixtt_regval);

    mutex_spinunlock(&hub_info->h_bwlock, s);
    return 0;
}

int
hubii_ixtt_get(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt)
{
    xwidget_info_t        widget_info = xwidget_info_get(widget_vhdl);
    devfs_handle_t        hub_vhdl    = xwidget_info_master_get(widget_info);
    hubinfo_t        hub_info = 0;
    nasid_t            nasid;
    unsigned long        s;

    /* Use the nasid from the hub info hanging off the hub vertex
     * and widget number from the widget vertex
     */
    hubinfo_get(hub_vhdl, &hub_info);
    /* Being over cautious by grabbing a lock */
    s     = mutex_spinlock(&hub_info->h_bwlock);
    nasid     = hub_info->h_nasid;

    ixtt->ii_ixtt_regval = REMOTE_HUB_L(nasid, IIO_IXTT);

    mutex_spinunlock(&hub_info->h_bwlock, s);
    return 0;
}
#endif /* CONFIG_IA64_SGI_SN1 */

/*
 * hub_device_inquiry
 *    Find out the xtalk widget related information stored in this 
 *    hub's II.
 */
void
hub_device_inquiry(devfs_handle_t    xbus_vhdl, xwidgetnum_t widget)
{
    devfs_handle_t    xconn, hub_vhdl;
    char        widget_name[8];
    hubreg_t    ii_iidem,ii_iiwa, ii_iowa;
    hubinfo_t    hubinfo;
    nasid_t        nasid;
    int        d;

    sprintf(widget_name, "%d", widget);
    if (hwgraph_traverse(xbus_vhdl, widget_name, &xconn)
        != GRAPH_SUCCESS)
        return;

    hub_vhdl = device_master_get(xconn);
    if (hub_vhdl == GRAPH_VERTEX_NONE)
        return;

    hubinfo_get(hub_vhdl, &hubinfo);
    if (!hubinfo)
        return;
    
    nasid = hubinfo->h_nasid;

    ii_iidem    = REMOTE_HUB_L(nasid, IIO_IIDEM);
    ii_iiwa     = REMOTE_HUB_L(nasid, IIO_IIWA);
    ii_iowa     = REMOTE_HUB_L(nasid, IIO_IOWA);

#if defined(SUPPORT_PRINTING_V_FORMAT)
    printk("Inquiry Info for %v\n", xconn);
#else
    printk("Inquiry Info for 0x%x\n", xconn);
#endif

    printk("\tDevices shutdown [ ");

    for (d = 0 ; d <= 7 ; d++)
        if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d))))
            printk(" %d", d);

    printk("]\n");

    printk("\tInbound access ? %s\n",
        ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no");

    printk("\tOutbound access ? %s\n",
        ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no");

}

/*
 * 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 = {
    (xtalk_piomap_alloc_f *)    hub_piomap_alloc,
    (xtalk_piomap_free_f *)        hub_piomap_free,
    (xtalk_piomap_addr_f *)        hub_piomap_addr,
    (xtalk_piomap_done_f *)        hub_piomap_done,
    (xtalk_piotrans_addr_f *)    hub_piotrans_addr,

    (xtalk_dmamap_alloc_f *)    hub_dmamap_alloc,
    (xtalk_dmamap_free_f *)        hub_dmamap_free,
    (xtalk_dmamap_addr_f *)        hub_dmamap_addr,
    (xtalk_dmamap_list_f *)        hub_dmamap_list,
    (xtalk_dmamap_done_f *)        hub_dmamap_done,
    (xtalk_dmatrans_addr_f *)    hub_dmatrans_addr,
    (xtalk_dmatrans_list_f *)    hub_dmatrans_list,
    (xtalk_dmamap_drain_f *)    hub_dmamap_drain,
    (xtalk_dmaaddr_drain_f *)    hub_dmaaddr_drain,
    (xtalk_dmalist_drain_f *)    hub_dmalist_drain,

    (xtalk_intr_alloc_f *)        hub_intr_alloc,
    (xtalk_intr_alloc_f *)        hub_intr_alloc_nothd,
    (xtalk_intr_free_f *)        hub_intr_free,
    (xtalk_intr_connect_f *)    hub_intr_connect,
    (xtalk_intr_disconnect_f *)    hub_intr_disconnect,
    (xtalk_intr_cpu_get_f *)    hub_intr_cpu_get,

    (xtalk_provider_startup_f *)    hub_provider_startup,
    (xtalk_provider_shutdown_f *)    hub_provider_shutdown,
};


:: 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.0065 ]--