static int tsi721_map_outb_win()

in devices/tsi721.c [919:1000]


static int tsi721_map_outb_win(struct rio_mport *mport, u16 destid, u64 rstart,
			u32 size, u32 flags, dma_addr_t *laddr)
{
	struct tsi721_device *priv = mport->priv;
	int i;
	struct tsi721_obw_bar *pbar;
	struct tsi721_ob_win *ob_win;
	int obw = -1;
	u32 rval;
	u64 rio_addr;
	u32 zsize;
	int ret = -ENOMEM;

	tsi_debug(OBW, &priv->pdev->dev,
		  "did=%d ra=0x%llx sz=0x%x", destid, rstart, size);

	if (!is_power_of_2(size) || (size < 0x8000) || (rstart & (size - 1)))
		return -EINVAL;

	if (priv->obwin_cnt == 0)
		return -EBUSY;

	for (i = 0; i < 2; i++) {
		if (priv->p2r_bar[i].free >= size) {
			pbar = &priv->p2r_bar[i];
			ret = tsi721_obw_alloc(priv, pbar, size, &obw);
			if (!ret)
				break;
		}
	}

	if (ret)
		return ret;

	WARN_ON(obw == -1);
	ob_win = &priv->ob_win[obw];
	ob_win->destid = destid;
	ob_win->rstart = rstart;
	tsi_debug(OBW, &priv->pdev->dev,
		  "allocated OBW%d @%llx", obw, ob_win->base);

	/*
	 * Configure Outbound Window
	 */

	zsize = size/TSI721_PC2SR_ZONES;
	rio_addr = rstart;

	/*
	 * Program Address Translation Zones:
	 *  This implementation uses all 8 zones associated wit window.
	 */
	for (i = 0; i < TSI721_PC2SR_ZONES; i++) {

		while (ioread32(priv->regs + TSI721_ZONE_SEL) &
			TSI721_ZONE_SEL_GO) {
			udelay(1);
		}

		rval = (u32)(rio_addr & TSI721_LUT_DATA0_ADD) |
			TSI721_LUT_DATA0_NREAD | TSI721_LUT_DATA0_NWR;
		iowrite32(rval, priv->regs + TSI721_LUT_DATA0);
		rval = (u32)(rio_addr >> 32);
		iowrite32(rval, priv->regs + TSI721_LUT_DATA1);
		rval = destid;
		iowrite32(rval, priv->regs + TSI721_LUT_DATA2);

		rval = TSI721_ZONE_SEL_GO | (obw << 3) | i;
		iowrite32(rval, priv->regs + TSI721_ZONE_SEL);

		rio_addr += zsize;
	}

	iowrite32(TSI721_OBWIN_SIZE(size) << 8,
		  priv->regs + TSI721_OBWINSZ(obw));
	iowrite32((u32)(ob_win->base >> 32), priv->regs + TSI721_OBWINUB(obw));
	iowrite32((u32)(ob_win->base & TSI721_OBWINLB_BA) | TSI721_OBWINLB_WEN,
		  priv->regs + TSI721_OBWINLB(obw));

	*laddr = ob_win->base;
	return 0;
}