コード例 #1
0
ファイル: solo6010-p2m.c プロジェクト: srstrong/solo6x10
/* Mutex must be held for p2m_id before calling this!! */
int solo_p2m_dma_desc(struct solo6010_dev *solo_dev,
		      struct solo_p2m_desc *desc, dma_addr_t desc_dma,
		      int desc_cnt)
{
	struct solo_p2m_dev *p2m_dev;
	unsigned int timeout = 0;
	unsigned int config = 0;
	int ret = 0;
        int p2m_id;

	/* Get next ID */
	p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M;
	if (p2m_id < 0)
		p2m_id = 0 - p2m_id;

	p2m_dev = &solo_dev->p2m_dev[p2m_id];

	if (mutex_lock_interruptible(&p2m_dev->mutex))
		return -EINTR;

	INIT_COMPLETION(p2m_dev->completion);
	p2m_dev->error = 0;

	if (desc_cnt > 1) {
		/* We only need to do this when we have more than one
		 * descriptor. */
		config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id));

		solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma);
		solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt);
		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config |
			       SOLO_P2M_DESC_MODE);
	} else {
		solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), desc[1].dma_addr);
		solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), desc[1].ext_addr);
		solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), desc[1].cfg);
		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), desc[1].ctrl);
	}

	timeout = wait_for_completion_timeout(&p2m_dev->completion,
					      msecs_to_jiffies(solo_dev->p2m_msecs));

	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0);

	if (desc_cnt > 1)
		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config);

	if (WARN_ON_ONCE(p2m_dev->error))
		ret = -EIO;
	else if (timeout == 0)
		ret = -EAGAIN;

	mutex_unlock(&p2m_dev->mutex);

	return ret;
}
コード例 #2
0
int solo_p2m_dma_t(struct solo6010_dev *solo_dev, u8 id, int wr,
                   dma_addr_t dma_addr, u32 ext_addr, u32 size)
{
    struct solo_p2m_dev *p2m_dev;
    unsigned int timeout = 0;

    WARN_ON(!size);
    WARN_ON(id >= SOLO_NR_P2M);
    if (!size || id >= SOLO_NR_P2M)
        return -EINVAL;

    p2m_dev = &solo_dev->p2m_dev[id];

    down(&p2m_dev->sem);

start_dma:
    INIT_COMPLETION(p2m_dev->completion);
    p2m_dev->error = 0;
    solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), dma_addr);
    solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), ext_addr);
    solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id),
                   SOLO_P2M_COPY_SIZE(size >> 2));
    solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id),
                   SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
                   (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON);

    timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ);

    solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);

    /* XXX Really looks to me like we will get stuck here if a
     * real PCI P2M error occurs */
    if (p2m_dev->error)
        goto start_dma;

    up(&p2m_dev->sem);

    return (timeout == 0) ? -EAGAIN : 0;
}