/* 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_init(struct solo6010_dev *solo_dev) { struct solo_p2m_dev *p2m_dev; int i; for (i = 0; i < SOLO_NR_P2M; i++) { p2m_dev = &solo_dev->p2m_dev[i]; sema_init(&p2m_dev->sem, 1); init_completion(&p2m_dev->completion); solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(i), __pa(p2m_dev->desc)); solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), SOLO_P2M_CSC_16BIT_565 | SOLO_P2M_DMA_INTERVAL(0) | SOLO_P2M_PCI_MASTER_MODE); solo6010_irq_on(solo_dev, SOLO_IRQ_P2M(i)); } run_p2m_test(solo_dev); return 0; }