Пример #1
0
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
		      int len, int directed)
{
	struct cpdma_ctlr		*ctlr = chan->ctlr;
	struct cpdma_desc __iomem	*desc;
	dma_addr_t			buffer;
	unsigned long			flags;
	u32				mode;
	int				ret = 0;

	spin_lock_irqsave(&chan->lock, flags);

	if (chan->state == CPDMA_STATE_TEARDOWN) {
		ret = -EINVAL;
		goto unlock_ret;
	}

	desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
	if (!desc) {
		chan->stats.desc_alloc_fail++;
		ret = -ENOMEM;
		goto unlock_ret;
	}

	if (len < ctlr->params.min_packet_size) {
		len = ctlr->params.min_packet_size;
		chan->stats.runt_transmit_buff++;
	}

	buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
	ret = dma_mapping_error(ctlr->dev, buffer);
	if (ret) {
		cpdma_desc_free(ctlr->pool, desc, 1);
		ret = -EINVAL;
		goto unlock_ret;
	}

	mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
	cpdma_desc_to_port(chan, mode, directed);

	desc_write(desc, hw_next,   0);
	desc_write(desc, hw_buffer, buffer);
	desc_write(desc, hw_len,    len);
	desc_write(desc, hw_mode,   mode | len);
	desc_write(desc, sw_token,  token);
	desc_write(desc, sw_buffer, buffer);
	desc_write(desc, sw_len,    len);

	__cpdma_chan_submit(chan, desc);

	if (chan->state == CPDMA_STATE_ACTIVE && chan->rxfree)
		chan_write(chan, rxfree, 1);

	chan->count++;

unlock_ret:
	spin_unlock_irqrestore(&chan->lock, flags);
	return ret;
}
Пример #2
0
struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
				     cpdma_handler_fn handler)
{
	struct cpdma_chan *chan;
	int ret, offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;
	unsigned long flags;

	if (__chan_linear(chan_num) >= ctlr->num_chan)
		return NULL;

	ret = -ENOMEM;
	chan = kzalloc(sizeof(*chan), GFP_KERNEL);
	if (!chan)
		goto err_chan_alloc;

	spin_lock_irqsave(&ctlr->lock, flags);
	ret = -EBUSY;
	if (ctlr->channels[chan_num])
		goto err_chan_busy;

	chan->ctlr	= ctlr;
	chan->state	= CPDMA_STATE_IDLE;
	chan->chan_num	= chan_num;
	chan->handler	= handler;

	if (is_rx_chan(chan)) {
		chan->hdp	= ctlr->params.rxhdp + offset;
		chan->cp	= ctlr->params.rxcp + offset;
		chan->rxfree	= ctlr->params.rxfree + offset;
		chan->int_set	= CPDMA_RXINTMASKSET;
		chan->int_clear	= CPDMA_RXINTMASKCLEAR;
		chan->td	= CPDMA_RXTEARDOWN;
		chan->dir	= DMA_FROM_DEVICE;
	} else {
		chan->hdp	= ctlr->params.txhdp + offset;
		chan->cp	= ctlr->params.txcp + offset;
		chan->int_set	= CPDMA_TXINTMASKSET;
		chan->int_clear	= CPDMA_TXINTMASKCLEAR;
		chan->td	= CPDMA_TXTEARDOWN;
		chan->dir	= DMA_TO_DEVICE;
	}
	chan->mask = BIT(chan_linear(chan));

	spin_lock_init(&chan->lock);

	ctlr->channels[chan_num] = chan;
	spin_unlock_irqrestore(&ctlr->lock, flags);
	return chan;

err_chan_busy:
	spin_unlock_irqrestore(&ctlr->lock, flags);
	kfree(chan);
err_chan_alloc:
	return ERR_PTR(ret);
}
Пример #3
0
int cpdma_chan_dump(struct cpdma_chan *chan)
{
	unsigned long flags;
	struct device *dev = chan->ctlr->dev;

	spin_lock_irqsave(&chan->lock, flags);

	dev_info(dev, "channel %d (%s %d) state %s",
		 chan->chan_num, is_rx_chan(chan) ? "rx" : "tx",
		 chan_linear(chan), cpdma_state_str[chan->state]);
	dev_info(dev, "\thdp: %x\n", chan_read(chan, hdp));
	dev_info(dev, "\tcp: %x\n", chan_read(chan, cp));
	if (chan->rxfree) {
		dev_info(dev, "\trxfree: %x\n",
			 chan_read(chan, rxfree));
	}

	dev_info(dev, "\tstats head_enqueue: %d\n",
		 chan->stats.head_enqueue);
	dev_info(dev, "\tstats tail_enqueue: %d\n",
		 chan->stats.tail_enqueue);
	dev_info(dev, "\tstats pad_enqueue: %d\n",
		 chan->stats.pad_enqueue);
	dev_info(dev, "\tstats misqueued: %d\n",
		 chan->stats.misqueued);
	dev_info(dev, "\tstats desc_alloc_fail: %d\n",
		 chan->stats.desc_alloc_fail);
	dev_info(dev, "\tstats pad_alloc_fail: %d\n",
		 chan->stats.pad_alloc_fail);
	dev_info(dev, "\tstats runt_receive_buff: %d\n",
		 chan->stats.runt_receive_buff);
	dev_info(dev, "\tstats runt_transmit_buff: %d\n",
		 chan->stats.runt_transmit_buff);
	dev_info(dev, "\tstats empty_dequeue: %d\n",
		 chan->stats.empty_dequeue);
	dev_info(dev, "\tstats busy_dequeue: %d\n",
		 chan->stats.busy_dequeue);
	dev_info(dev, "\tstats good_dequeue: %d\n",
		 chan->stats.good_dequeue);
	dev_info(dev, "\tstats requeue: %d\n",
		 chan->stats.requeue);
	dev_info(dev, "\tstats teardown_dequeue: %d\n",
		 chan->stats.teardown_dequeue);

	spin_unlock_irqrestore(&chan->lock, flags);
	return 0;
}