Ejemplo n.º 1
0
/**
 * hub_pio_map  -  establish a HUB PIO mapping
 *
 * @hub:	hub to perform PIO mapping on
 * @widget:	widget ID to perform PIO mapping for
 * @xtalk_addr:	xtalk_address that needs to be mapped
 * @size:	size of the PIO mapping
 *
 **/
unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
			  unsigned long xtalk_addr, size_t size)
{
	nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
	volatile hubreg_t junk;
	unsigned i;

	/* use small-window mapping if possible */
	if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE)
		return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE);

	if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) {
		printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx"
				" too big (%ld)\n",
				nasid, widget, xtalk_addr, size);
		return 0;
	}

	xtalk_addr &= ~(BWIN_SIZE-1);
	for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) {
		if (test_and_set_bit(i, hub_data(cnode)->h_bigwin_used))
			continue;

		/*
		 * 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.
		 */
		IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
		junk = HUB_L(IIO_ITTE_GET(nasid, i));

		return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
	}

	printk(KERN_WARNING "unable to establish PIO mapping for at"
			" hub %d widget %d addr 0x%lx\n",
			nasid, widget, xtalk_addr);
	return 0;
}
Ejemplo n.º 2
0
/* 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;
    int 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, PZERO, &hubinfo->h_bwlock, s);
            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);
}