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