]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/net/ethernet/ti/davinci_cpdma.c
Merge tag 'multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-beck.git] / drivers / net / ethernet / ti / davinci_cpdma.c
index 1abe0964a5ab832c1b9aec65ab608d798c0acc4d..ee13dc78430c18f542d4a59dad5d9d09a8256b8c 100644 (file)
@@ -60,6 +60,9 @@
 #define CPDMA_DESC_EOQ         BIT(28)
 #define CPDMA_DESC_TD_COMPLETE BIT(27)
 #define CPDMA_DESC_PASS_CRC    BIT(26)
+#define CPDMA_DESC_TO_PORT_EN  BIT(20)
+#define CPDMA_TO_PORT_SHIFT    16
+#define CPDMA_DESC_PORT_MASK   (BIT(18) | BIT(17) | BIT(16))
 
 #define CPDMA_TEARDOWN_VALUE   0xfffffffc
 
@@ -105,13 +108,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;
@@ -132,6 +135,14 @@ struct cpdma_chan {
 #define chan_write(chan, fld, v)       __raw_writel(v, (chan)->fld)
 #define desc_write(desc, fld, v)       __raw_writel((u32)(v), &(desc)->fld)
 
+#define cpdma_desc_to_port(chan, mode, directed)                       \
+       do {                                                            \
+               if (!is_rx_chan(chan) && ((directed == 1) ||            \
+                                         (directed == 2)))             \
+                       mode |= (CPDMA_DESC_TO_PORT_EN |                \
+                                (directed << CPDMA_TO_PORT_SHIFT));    \
+       } while (0)
+
 /*
  * Utility constructs for a cpdma descriptor pool.  Some devices (e.g. davinci
  * emac) have dedicated on-chip memory for these descriptors.  Some other
@@ -217,17 +228,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++;
@@ -439,10 +460,8 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr)
        if (ctlr->state != CPDMA_STATE_IDLE)
                cpdma_ctlr_stop(ctlr);
 
-       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
-               if (ctlr->channels[i])
-                       cpdma_chan_destroy(ctlr->channels[i]);
-       }
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++)
+               cpdma_chan_destroy(ctlr->channels[i]);
 
        cpdma_desc_pool_destroy(ctlr->pool);
        spin_unlock_irqrestore(&ctlr->lock, flags);
@@ -475,9 +494,9 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable)
 }
 EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl);
 
-void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr)
+void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
 {
-       dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0);
+       dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value);
 }
 EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi);
 
@@ -654,7 +673,7 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan,
 }
 
 int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
-                     int len, gfp_t gfp_mask)
+                     int len, int directed, gfp_t gfp_mask)
 {
        struct cpdma_ctlr               *ctlr = chan->ctlr;
        struct cpdma_desc __iomem       *desc;
@@ -670,7 +689,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;
@@ -684,6 +703,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
 
        buffer = dma_map_single(ctlr->dev, data, len, chan->dir);
        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);
@@ -706,6 +726,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)
@@ -751,7 +794,8 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
                status = -EBUSY;
                goto unlock_ret;
        }
-       status  = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE);
+       status  = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE |
+                           CPDMA_DESC_PORT_MASK);
 
        chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
        chan_write(chan, cp, desc_dma);