|
@@ -105,13 +105,13 @@ struct cpdma_ctlr {
|
|
|
};
|
|
|
|
|
|
struct cpdma_chan {
|
|
|
+ struct cpdma_desc __iomem *head, *tail;
|
|
|
+ void __iomem *hdp, *cp, *rxfree;
|
|
|
enum cpdma_state state;
|
|
|
struct cpdma_ctlr *ctlr;
|
|
|
int chan_num;
|
|
|
spinlock_t lock;
|
|
|
- struct cpdma_desc __iomem *head, *tail;
|
|
|
int count;
|
|
|
- void __iomem *hdp, *cp, *rxfree;
|
|
|
u32 mask;
|
|
|
cpdma_handler_fn handler;
|
|
|
enum dma_data_direction dir;
|
|
@@ -217,17 +217,27 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma)
|
|
|
}
|
|
|
|
|
|
static struct cpdma_desc __iomem *
|
|
|
-cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc)
|
|
|
+cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx)
|
|
|
{
|
|
|
unsigned long flags;
|
|
|
int index;
|
|
|
+ int desc_start;
|
|
|
+ int desc_end;
|
|
|
struct cpdma_desc __iomem *desc = NULL;
|
|
|
|
|
|
spin_lock_irqsave(&pool->lock, flags);
|
|
|
|
|
|
- index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0,
|
|
|
- num_desc, 0);
|
|
|
- if (index < pool->num_desc) {
|
|
|
+ if (is_rx) {
|
|
|
+ desc_start = 0;
|
|
|
+ desc_end = pool->num_desc/2;
|
|
|
+ } else {
|
|
|
+ desc_start = pool->num_desc/2;
|
|
|
+ desc_end = pool->num_desc;
|
|
|
+ }
|
|
|
+
|
|
|
+ index = bitmap_find_next_zero_area(pool->bitmap,
|
|
|
+ desc_end, desc_start, num_desc, 0);
|
|
|
+ if (index < desc_end) {
|
|
|
bitmap_set(pool->bitmap, index, num_desc);
|
|
|
desc = pool->iomap + pool->desc_size * index;
|
|
|
pool->used_desc++;
|
|
@@ -668,7 +678,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
|
|
|
goto unlock_ret;
|
|
|
}
|
|
|
|
|
|
- desc = cpdma_desc_alloc(ctlr->pool, 1);
|
|
|
+ desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan));
|
|
|
if (!desc) {
|
|
|
chan->stats.desc_alloc_fail++;
|
|
|
ret = -ENOMEM;
|
|
@@ -704,6 +714,29 @@ unlock_ret:
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(cpdma_chan_submit);
|
|
|
|
|
|
+bool cpdma_check_free_tx_desc(struct cpdma_chan *chan)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ int index;
|
|
|
+ bool ret;
|
|
|
+ struct cpdma_ctlr *ctlr = chan->ctlr;
|
|
|
+ struct cpdma_desc_pool *pool = ctlr->pool;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&pool->lock, flags);
|
|
|
+
|
|
|
+ index = bitmap_find_next_zero_area(pool->bitmap,
|
|
|
+ pool->num_desc, pool->num_desc/2, 1, 0);
|
|
|
+
|
|
|
+ if (index < pool->num_desc)
|
|
|
+ ret = true;
|
|
|
+ else
|
|
|
+ ret = false;
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&pool->lock, flags);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc);
|
|
|
+
|
|
|
static void __cpdma_chan_free(struct cpdma_chan *chan,
|
|
|
struct cpdma_desc __iomem *desc,
|
|
|
int outlen, int status)
|