Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / ti / davinci_cpdma.c
index 19e5f32..c3f35f1 100644 (file)
@@ -86,7 +86,7 @@ struct cpdma_desc_pool {
        void __iomem            *iomap;         /* ioremap map */
        void                    *cpumap;        /* dma_alloc map */
        int                     desc_size, mem_size;
-       int                     num_desc, used_desc;
+       int                     num_desc;
        struct device           *dev;
        struct gen_pool         *gen_pool;
 };
@@ -104,6 +104,7 @@ struct cpdma_ctlr {
        struct cpdma_desc_pool  *pool;
        spinlock_t              lock;
        struct cpdma_chan       *channels[2 * CPDMA_MAX_CHANNELS];
+       int chan_num;
 };
 
 struct cpdma_chan {
@@ -123,6 +124,13 @@ struct cpdma_chan {
        int     int_set, int_clear, td;
 };
 
+#define tx_chan_num(chan)      (chan)
+#define rx_chan_num(chan)      ((chan) + CPDMA_MAX_CHANNELS)
+#define is_rx_chan(chan)       ((chan)->chan_num >= CPDMA_MAX_CHANNELS)
+#define is_tx_chan(chan)       (!is_rx_chan(chan))
+#define __chan_linear(chan_num)        ((chan_num) & (CPDMA_MAX_CHANNELS - 1))
+#define chan_linear(chan)      __chan_linear((chan)->chan_num)
+
 /* The following make access to common cpdma_ctlr params more readable */
 #define dmaregs                params.dmaregs
 #define num_chan       params.num_chan
@@ -148,7 +156,10 @@ static void cpdma_desc_pool_destroy(struct cpdma_desc_pool *pool)
        if (!pool)
                return;
 
-       WARN_ON(pool->used_desc);
+       WARN(gen_pool_size(pool->gen_pool) != gen_pool_avail(pool->gen_pool),
+            "cpdma_desc_pool size %d != avail %d",
+            gen_pool_size(pool->gen_pool),
+            gen_pool_avail(pool->gen_pool));
        if (pool->cpumap)
                dma_free_coherent(pool->dev, pool->mem_size, pool->cpumap,
                                  pool->phys);
@@ -232,21 +243,14 @@ 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)
 {
-       struct cpdma_desc __iomem *desc = NULL;
-
-       desc = (struct cpdma_desc __iomem *)gen_pool_alloc(pool->gen_pool,
-                                                          pool->desc_size);
-       if (desc)
-               pool->used_desc++;
-
-       return desc;
+       return (struct cpdma_desc __iomem *)
+               gen_pool_alloc(pool->gen_pool, pool->desc_size);
 }
 
 static void cpdma_desc_free(struct cpdma_desc_pool *pool,
                            struct cpdma_desc __iomem *desc, int num_desc)
 {
        gen_pool_free(pool->gen_pool, (unsigned long)desc, pool->desc_size);
-       pool->used_desc--;
 }
 
 struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
@@ -260,6 +264,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params)
        ctlr->state = CPDMA_STATE_IDLE;
        ctlr->params = *params;
        ctlr->dev = params->dev;
+       ctlr->chan_num = 0;
        spin_lock_init(&ctlr->lock);
 
        ctlr->pool = cpdma_desc_pool_create(ctlr->dev,
@@ -336,12 +341,14 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
        }
 
        ctlr->state = CPDMA_STATE_TEARDOWN;
+       spin_unlock_irqrestore(&ctlr->lock, flags);
 
        for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
                if (ctlr->channels[i])
                        cpdma_chan_stop(ctlr->channels[i]);
        }
 
+       spin_lock_irqsave(&ctlr->lock, flags);
        dma_reg_write(ctlr, CPDMA_RXINTMASKCLEAR, 0xffffffff);
        dma_reg_write(ctlr, CPDMA_TXINTMASKCLEAR, 0xffffffff);
 
@@ -403,13 +410,52 @@ void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value)
 }
 EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi);
 
+u32 cpdma_ctrl_rxchs_state(struct cpdma_ctlr *ctlr)
+{
+       return dma_reg_read(ctlr, CPDMA_RXINTSTATMASKED);
+}
+EXPORT_SYMBOL_GPL(cpdma_ctrl_rxchs_state);
+
+u32 cpdma_ctrl_txchs_state(struct cpdma_ctlr *ctlr)
+{
+       return dma_reg_read(ctlr, CPDMA_TXINTSTATMASKED);
+}
+EXPORT_SYMBOL_GPL(cpdma_ctrl_txchs_state);
+
+/**
+ * cpdma_chan_split_pool - Splits ctrl pool between all channels.
+ * Has to be called under ctlr lock
+ */
+static void cpdma_chan_split_pool(struct cpdma_ctlr *ctlr)
+{
+       struct cpdma_desc_pool *pool = ctlr->pool;
+       struct cpdma_chan *chan;
+       int ch_desc_num;
+       int i;
+
+       if (!ctlr->chan_num)
+               return;
+
+       /* calculate average size of pool slice */
+       ch_desc_num = pool->num_desc / ctlr->chan_num;
+
+       /* split ctlr pool */
+       for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) {
+               chan = ctlr->channels[i];
+               if (chan)
+                       chan->desc_num = ch_desc_num;
+       }
+}
+
 struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
-                                    cpdma_handler_fn handler)
+                                    cpdma_handler_fn handler, int rx_type)
 {
+       int offset = chan_num * 4;
        struct cpdma_chan *chan;
-       int offset = (chan_num % CPDMA_MAX_CHANNELS) * 4;
        unsigned long flags;
 
+       chan_num = rx_type ? rx_chan_num(chan_num) : tx_chan_num(chan_num);
+
        if (__chan_linear(chan_num) >= ctlr->num_chan)
                return NULL;
 
@@ -451,14 +497,25 @@ struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num,
        spin_lock_init(&chan->lock);
 
        ctlr->channels[chan_num] = chan;
+       ctlr->chan_num++;
+
+       cpdma_chan_split_pool(ctlr);
+
        spin_unlock_irqrestore(&ctlr->lock, flags);
        return chan;
 }
 EXPORT_SYMBOL_GPL(cpdma_chan_create);
 
-int cpdma_chan_get_rx_buf_num(struct cpdma_ctlr *ctlr)
+int cpdma_chan_get_rx_buf_num(struct cpdma_chan *chan)
 {
-       return ctlr->pool->num_desc / 2;
+       unsigned long flags;
+       int desc_num;
+
+       spin_lock_irqsave(&chan->lock, flags);
+       desc_num = chan->desc_num;
+       spin_unlock_irqrestore(&chan->lock, flags);
+
+       return desc_num;
 }
 EXPORT_SYMBOL_GPL(cpdma_chan_get_rx_buf_num);
 
@@ -475,6 +532,10 @@ int cpdma_chan_destroy(struct cpdma_chan *chan)
        if (chan->state != CPDMA_STATE_IDLE)
                cpdma_chan_stop(chan);
        ctlr->channels[chan->chan_num] = NULL;
+       ctlr->chan_num--;
+
+       cpdma_chan_split_pool(ctlr);
+
        spin_unlock_irqrestore(&ctlr->lock, flags);
        return 0;
 }