aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c')
-rw-r--r--target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c1206
1 files changed, 0 insertions, 1206 deletions
diff --git a/target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c b/target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c
deleted file mode 100644
index 7464be1bd5..0000000000
--- a/target/linux/lantiq/files-3.3/arch/mips/lantiq/svip/dma.c
+++ /dev/null
@@ -1,1206 +0,0 @@
-/*
- ** Copyright (C) 2005 Wu Qi Ming <Qi-Ming.Wu@infineon.com>
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-/*
- * Description:
- * Driver for SVIP DMA
- * Author: Wu Qi Ming[Qi-Ming.Wu@infineon.com]
- * Created: 26-September-2005
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/selection.h>
-#include <linux/kmod.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/semaphore.h>
-
-#include <base_reg.h>
-#include <mps_reg.h>
-#include <dma_reg.h>
-#include <svip_dma.h>
-#include <lantiq_soc.h>
-#include <irq.h>
-#include <sys1_reg.h>
-
-static struct svip_reg_sys1 *const sys1 = (struct svip_reg_sys1 *)LTQ_SYS1_BASE;
-static struct svip_reg_dma *const dma = (struct svip_reg_dma *)LTQ_DMA_BASE;
-static struct svip_reg_mbs *const mbs = (struct svip_reg_mbs *)LTQ_MBS_BASE;
-
-#define DRV_NAME "ltq_dma"
-extern void ltq_mask_and_ack_irq(struct irq_data *data);
-extern void ltq_enable_irq(struct irq_data *data);
-
-static inline void mask_and_ack_irq(unsigned int irq_nr)
-{
- static int i = 0;
- struct irq_data data;
- data.irq = irq_nr;
- if ((i < 2) && (irq_nr == 137)) {
- printk("eth delay hack\n");
- i++;
- }
- ltq_mask_and_ack_irq(&data);
-}
-
-static inline void svip_enable_irq(unsigned int irq_nr)
-{
- struct irq_data data;
- data.irq = irq_nr;
- ltq_enable_irq(&data);
-}
-
-#define DMA_EMSG(fmt, args...) \
- printk(KERN_ERR "%s: " fmt, __func__, ## args)
-
-static inline void mbs_grab(void)
-{
- while (mbs_r32(mbsr0) != 0);
-}
-
-static inline void mbs_release(void)
-{
- mbs_w32(0, mbsr0);
- asm("sync");
-}
-
-/* max ports connecting to dma */
-#define LTQ_MAX_DMA_DEVICE_NUM ARRAY_SIZE(dma_devices)
-/* max dma channels */
-#define LTQ_MAX_DMA_CHANNEL_NUM ARRAY_SIZE(dma_chan)
-
-/* bytes per descriptor */
-#define DMA_DESCR_SIZE 8
-
-#define DMA_DESCR_CH_SIZE (DMA_DESCR_NUM * DMA_DESCR_SIZE)
-#define DMA_DESCR_TOTAL_SIZE (LTQ_MAX_DMA_CHANNEL_NUM * DMA_DESCR_CH_SIZE)
-#define DMA_DESCR_MEM_PAGES ((DMA_DESCR_TOTAL_SIZE / PAGE_SIZE) + \
- (((DMA_DESCR_TOTAL_SIZE % PAGE_SIZE) > 0)))
-
-/* budget for interrupt handling */
-#define DMA_INT_BUDGET 100
-/* set the correct counter value here! */
-#define DMA_POLL_COUNTER 32
-
-struct proc_dir_entry *g_dma_dir;
-
-/* device_name | max_rx_chan_num | max_tx_chan_num | drop_enable */
-struct dma_device_info dma_devices[] = {
- { "SW", 4, 4, 0 },
- { "DEU", 1, 1, 0 },
- { "SSC0", 1, 1, 0 },
- { "SSC1", 1, 1, 0 },
- { "MCTRL", 1, 1, 0 },
- { "PCM0", 1, 1, 0 },
- { "PCM1", 1, 1, 0 },
- { "PCM2", 1, 1, 0 },
- { "PCM3", 1, 1, 0 }
-};
-
-/* *dma_dev | dir | pri | irq | rel_chan_no */
-struct dma_channel_info dma_chan[] = {
- { &dma_devices[0], DIR_RX, 0, INT_NUM_IM4_IRL0 + 0, 0 },
- { &dma_devices[0], DIR_TX, 0, INT_NUM_IM4_IRL0 + 1, 0 },
- { &dma_devices[0], DIR_RX, 1, INT_NUM_IM4_IRL0 + 2, 1 },
- { &dma_devices[0], DIR_TX, 1, INT_NUM_IM4_IRL0 + 3, 1 },
- { &dma_devices[0], DIR_RX, 2, INT_NUM_IM4_IRL0 + 4, 2 },
- { &dma_devices[0], DIR_TX, 2, INT_NUM_IM4_IRL0 + 5, 2 },
- { &dma_devices[0], DIR_RX, 3, INT_NUM_IM4_IRL0 + 6, 3 },
- { &dma_devices[0], DIR_TX, 3, INT_NUM_IM4_IRL0 + 7, 3 },
- { &dma_devices[1], DIR_RX, 0, INT_NUM_IM4_IRL0 + 8, 0 },
- { &dma_devices[1], DIR_TX, 0, INT_NUM_IM4_IRL0 + 9, 0 },
- { &dma_devices[2], DIR_RX, 0, INT_NUM_IM4_IRL0 + 10, 0 },
- { &dma_devices[2], DIR_TX, 0, INT_NUM_IM4_IRL0 + 11, 0 },
- { &dma_devices[3], DIR_RX, 0, INT_NUM_IM4_IRL0 + 12, 0 },
- { &dma_devices[3], DIR_TX, 0, INT_NUM_IM4_IRL0 + 13, 0 },
- { &dma_devices[4], DIR_RX, 0, INT_NUM_IM4_IRL0 + 14, 0 },
- { &dma_devices[4], DIR_TX, 0, INT_NUM_IM4_IRL0 + 15, 0 },
- { &dma_devices[5], DIR_RX, 0, INT_NUM_IM4_IRL0 + 16, 0 },
- { &dma_devices[5], DIR_TX, 0, INT_NUM_IM4_IRL0 + 17, 0 },
- { &dma_devices[6], DIR_RX, 1, INT_NUM_IM3_IRL0 + 18, 0 },
- { &dma_devices[6], DIR_TX, 1, INT_NUM_IM3_IRL0 + 19, 0 },
- { &dma_devices[7], DIR_RX, 2, INT_NUM_IM4_IRL0 + 20, 0 },
- { &dma_devices[7], DIR_TX, 2, INT_NUM_IM4_IRL0 + 21, 0 },
- { &dma_devices[8], DIR_RX, 3, INT_NUM_IM4_IRL0 + 22, 0 },
- { &dma_devices[8], DIR_TX, 3, INT_NUM_IM4_IRL0 + 23, 0 }
-};
-
-u64 *g_desc_list[DMA_DESCR_MEM_PAGES];
-
-volatile u32 g_dma_int_status = 0;
-
-/* 0 - not in process, 1 - in process */
-volatile int g_dma_in_process;
-
-int ltq_dma_init(void);
-void do_dma_tasklet(unsigned long);
-DECLARE_TASKLET(dma_tasklet, do_dma_tasklet, 0);
-irqreturn_t dma_interrupt(int irq, void *dev_id);
-
-u8 *common_buffer_alloc(int len, int *byte_offset, void **opt)
-{
- u8 *buffer = kmalloc(len * sizeof(u8), GFP_KERNEL);
- *byte_offset = 0;
- return buffer;
-}
-
-void common_buffer_free(u8 *dataptr, void *opt)
-{
- kfree(dataptr);
-}
-
-void enable_ch_irq(struct dma_channel_info *ch)
-{
- int chan_no = (int)(ch - dma_chan);
- unsigned long flag;
- u32 val;
-
- if (ch->dir == DIR_RX)
- val = DMA_CIE_DESCPT | DMA_CIE_DUR;
- else
- val = DMA_CIE_DESCPT;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32(val, cie);
- dma_w32_mask(0, 1 << chan_no, irnen);
- mbs_release();
- local_irq_restore(flag);
-
- svip_enable_irq(ch->irq);
-}
-
-void disable_ch_irq(struct dma_channel_info *ch)
-{
- unsigned long flag;
- int chan_no = (int)(ch - dma_chan);
-
- local_irq_save(flag);
- g_dma_int_status &= ~(1 << chan_no);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32(0, cie);
- mbs_release();
- dma_w32_mask(1 << chan_no, 0, irnen);
- local_irq_restore(flag);
-
- mask_and_ack_irq(ch->irq);
-}
-
-int open_chan(struct dma_channel_info *ch)
-{
- unsigned long flag;
- int j;
- int chan_no = (int)(ch - dma_chan);
- u8 *buffer;
- int byte_offset;
- struct rx_desc *rx_desc_p;
- struct tx_desc *tx_desc_p;
-
- if (ch->control == LTQ_DMA_CH_ON)
- return -1;
-
- if (ch->dir == DIR_RX) {
- for (j = 0; j < ch->desc_len; j++) {
- rx_desc_p = (struct rx_desc *)ch->desc_base+j;
- buffer = ch->dma_dev->buffer_alloc(ch->packet_size,
- &byte_offset,
- (void *)&ch->opt[j]);
- if (!buffer)
- return -ENOBUFS;
-
- rx_desc_p->data_pointer = (u32)CPHYSADDR((u32)buffer);
- rx_desc_p->status.word = 0;
- rx_desc_p->status.field.byte_offset = byte_offset;
- rx_desc_p->status.field.data_length = ch->packet_size;
- rx_desc_p->status.field.own = DMA_OWN;
- }
- } else {
- for (j = 0; j < ch->desc_len; j++) {
- tx_desc_p = (struct tx_desc *)ch->desc_base + j;
- tx_desc_p->data_pointer = 0;
- tx_desc_p->status.word = 0;
- }
- }
- ch->xfer_cnt = 0;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32(ch->desc_len, cdlen);
- dma_w32(0x7e, cis);
- dma_w32(DMA_CCTRL_TXWGT_VAL(ch->tx_weight)
- | DMA_CCTRL_CLASS_VAL(ch->pri)
- | (ch->dir == DIR_RX ? DMA_CCTRL_ON_OFF : 0), cctrl);
- mbs_release();
- ch->control = LTQ_DMA_CH_ON;
- local_irq_restore(flag);
-
- if (request_irq(ch->irq, dma_interrupt,
- IRQF_DISABLED, "dma-core", (void *)ch) != 0) {
- printk(KERN_ERR "error, cannot get dma_irq!\n");
- return -EFAULT;
- }
-
- enable_ch_irq(ch);
- return 0;
-}
-
-int close_chan(struct dma_channel_info *ch)
-{
- unsigned long flag;
- int j;
- int chan_no = (int)(ch - dma_chan);
- struct rx_desc *desc_p;
-
- if (ch->control == LTQ_DMA_CH_OFF)
- return -1;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32_mask(DMA_CCTRL_ON_OFF, 0, cctrl);
- mbs_release();
- disable_ch_irq(ch);
- free_irq(ch->irq, (void *)ch);
- ch->control = LTQ_DMA_CH_OFF;
- local_irq_restore(flag);
-
- /* free descriptors in use */
- for (j = 0; j < ch->desc_len; j++) {
- desc_p = (struct rx_desc *)ch->desc_base+j;
- if ((desc_p->status.field.own == CPU_OWN &&
- desc_p->status.field.c) ||
- (desc_p->status.field.own == DMA_OWN)) {
- if (desc_p->data_pointer) {
- ch->dma_dev->buffer_free((u8 *)__va(desc_p->data_pointer),
- (void *)ch->opt[j]);
- desc_p->data_pointer = (u32)NULL;
- }
- }
- }
-
- return 0;
-}
-
-int reset_chan(struct dma_channel_info *ch)
-{
- unsigned long flag;
- int val;
- int chan_no = (int)(ch - dma_chan);
-
- close_chan(ch);
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32_mask(0, DMA_CCTRL_RST, cctrl);
- mbs_release();
- local_irq_restore(flag);
-
- do {
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- val = dma_r32(cctrl);
- mbs_release();
- local_irq_restore(flag);
- } while (val & DMA_CCTRL_RST);
-
- return 0;
-}
-
-static inline void rx_chan_intr_handler(int chan_no)
-{
- struct dma_device_info *dma_dev = (struct dma_device_info *)
- dma_chan[chan_no].dma_dev;
- struct dma_channel_info *ch = &dma_chan[chan_no];
- struct rx_desc *rx_desc_p;
- unsigned long flag;
- u32 val;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- val = dma_r32(cis);
- dma_w32(DMA_CIS_DESCPT, cis);
- mbs_release();
-
- /* handle command complete interrupt */
- rx_desc_p = (struct rx_desc *)ch->desc_base + ch->curr_desc;
- if ((rx_desc_p->status.word & (DMA_DESC_OWN_DMA | DMA_DESC_CPT_SET)) ==
- DMA_DESC_CPT_SET) {
- local_irq_restore(flag);
- /* Every thing is correct, then we inform the upper layer */
- dma_dev->current_rx_chan = ch->rel_chan_no;
- if (dma_dev->intr_handler)
- dma_dev->intr_handler(dma_dev, RCV_INT);
- ch->weight--;
- } else {
- g_dma_int_status &= ~(1 << chan_no);
- local_irq_restore(flag);
- svip_enable_irq(dma_chan[chan_no].irq);
- }
-}
-
-static inline void tx_chan_intr_handler(int chan_no)
-{
- struct dma_device_info *dma_dev = (struct dma_device_info *)
- dma_chan[chan_no].dma_dev;
- struct dma_channel_info *ch = &dma_chan[chan_no];
- struct tx_desc *tx_desc_p;
- unsigned long flag;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32(DMA_CIS_DESCPT, cis);
- mbs_release();
-
- tx_desc_p = (struct tx_desc *)ch->desc_base+ch->prev_desc;
- if ((tx_desc_p->status.word & (DMA_DESC_OWN_DMA | DMA_DESC_CPT_SET)) ==
- DMA_DESC_CPT_SET) {
- local_irq_restore(flag);
-
- dma_dev->buffer_free((u8 *)__va(tx_desc_p->data_pointer),
- ch->opt[ch->prev_desc]);
- memset(tx_desc_p, 0, sizeof(struct tx_desc));
- dma_dev->current_tx_chan = ch->rel_chan_no;
- if (dma_dev->intr_handler)
- dma_dev->intr_handler(dma_dev, TRANSMIT_CPT_INT);
- ch->weight--;
-
- ch->prev_desc = (ch->prev_desc + 1) % (ch->desc_len);
- } else {
- g_dma_int_status &= ~(1 << chan_no);
- local_irq_restore(flag);
- svip_enable_irq(dma_chan[chan_no].irq);
- }
-}
-
-void do_dma_tasklet(unsigned long unused)
-{
- int i;
- int chan_no = 0;
- int budget = DMA_INT_BUDGET;
- int weight = 0;
- unsigned long flag;
-
- while (g_dma_int_status) {
- if (budget-- < 0) {
- tasklet_schedule(&dma_tasklet);
- return;
- }
- chan_no = -1;
- weight = 0;
- /* WFQ algorithm to select the channel */
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++) {
- if (g_dma_int_status & (1 << i) &&
- dma_chan[i].weight > 0) {
- if (dma_chan[i].weight > weight) {
- chan_no = i;
- weight = dma_chan[chan_no].weight;
- }
- }
- }
- if (chan_no >= 0) {
- if (dma_chan[chan_no].dir == DIR_RX)
- rx_chan_intr_handler(chan_no);
- else
- tx_chan_intr_handler(chan_no);
- } else {
- /* reset all the channels */
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++)
- dma_chan[i].weight = dma_chan[i].default_weight;
- }
- }
-
- local_irq_save(flag);
- g_dma_in_process = 0;
- if (g_dma_int_status) {
- g_dma_in_process = 1;
- tasklet_schedule(&dma_tasklet);
- }
- local_irq_restore(flag);
-}
-
-irqreturn_t dma_interrupt(int irq, void *dev_id)
-{
- struct dma_channel_info *ch;
- int chan_no = 0;
-
- ch = (struct dma_channel_info *)dev_id;
- chan_no = (int)(ch - dma_chan);
-
- if ((unsigned)chan_no >= LTQ_MAX_DMA_CHANNEL_NUM) {
- printk(KERN_ERR "error: dma_interrupt irq=%d chan_no=%d\n",
- irq, chan_no);
- }
-
- g_dma_int_status |= 1 << chan_no;
- dma_w32(1 << chan_no, irncr);
- mask_and_ack_irq(irq);
-
- if (!g_dma_in_process) {
- g_dma_in_process = 1;
- tasklet_schedule(&dma_tasklet);
- }
-
- return IRQ_RETVAL(1);
-}
-
-struct dma_device_info *dma_device_reserve(char *dev_name)
-{
- int i;
-
- ltq_dma_init();
- for (i = 0; i < LTQ_MAX_DMA_DEVICE_NUM; i++) {
- if (strcmp(dev_name, dma_devices[i].device_name) == 0) {
- if (dma_devices[i].reserved)
- return NULL;
- dma_devices[i].reserved = 1;
- break;
- }
- }
-
- if (i == LTQ_MAX_DMA_DEVICE_NUM)
- return NULL;
-
- return &dma_devices[i];
-}
-EXPORT_SYMBOL(dma_device_reserve);
-
-int dma_device_release(struct dma_device_info *dma_dev)
-{
- dma_dev->reserved = 0;
-
- return 0;
-}
-EXPORT_SYMBOL(dma_device_release);
-
-int dma_device_register(struct dma_device_info *dma_dev)
-{
- int port_no = (int)(dma_dev - dma_devices);
- int txbl, rxbl;
- unsigned long flag;
-
- switch (dma_dev->tx_burst_len) {
- case 8:
- txbl = 3;
- break;
- case 4:
- txbl = 2;
- break;
- default:
- txbl = 1;
- break;
- }
-
- switch (dma_dev->rx_burst_len) {
- case 8:
- rxbl = 3;
- break;
- case 4:
- rxbl = 2;
- break;
- default:
- rxbl = 1;
- }
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(port_no, ps);
- dma_w32(DMA_PCTRL_TXWGT_VAL(dma_dev->tx_weight)
- | DMA_PCTRL_TXENDI_VAL(dma_dev->tx_endianness_mode)
- | DMA_PCTRL_RXENDI_VAL(dma_dev->rx_endianness_mode)
- | DMA_PCTRL_PDEN_VAL(dma_dev->drop_enable)
- | DMA_PCTRL_TXBL_VAL(txbl)
- | DMA_PCTRL_RXBL_VAL(rxbl), pctrl);
- mbs_release();
- local_irq_restore(flag);
-
- return 0;
-}
-EXPORT_SYMBOL(dma_device_register);
-
-int dma_device_unregister(struct dma_device_info *dma_dev)
-{
- int i;
- int port_no = (int)(dma_dev - dma_devices);
- unsigned long flag;
-
- /* flush memcopy module; has no effect for other ports */
- local_irq_save(flag);
- mbs_grab();
- dma_w32(port_no, ps);
- dma_w32_mask(0, DMA_PCTRL_GPC, pctrl);
- mbs_release();
- local_irq_restore(flag);
-
- for (i = 0; i < dma_dev->max_tx_chan_num; i++)
- reset_chan(dma_dev->tx_chan[i]);
-
- for (i = 0; i < dma_dev->max_rx_chan_num; i++)
- reset_chan(dma_dev->rx_chan[i]);
-
- return 0;
-}
-EXPORT_SYMBOL(dma_device_unregister);
-
-/**
- * Read Packet from DMA Rx channel.
- * The function gets the data from the current rx descriptor assigned
- * to the passed DMA device and passes it back to the caller.
- * The function is called in the context of DMA interrupt.
- * In detail the following actions are done:
- * - get current receive descriptor
- * - allocate memory via allocation callback function
- * - pass data from descriptor to allocated memory
- * - update channel weight
- * - release descriptor
- * - update current descriptor position
- *
- * \param *dma_dev - pointer to DMA device structure
- * \param **dataptr - pointer to received data
- * \param **opt
- * \return packet length - length of received data
- * \ingroup Internal
- */
-int dma_device_read(struct dma_device_info *dma_dev, u8 **dataptr, void **opt)
-{
- u8 *buf;
- int len;
- int byte_offset = 0;
- void *p = NULL;
-
- struct dma_channel_info *ch =
- dma_dev->rx_chan[dma_dev->current_rx_chan];
-
- struct rx_desc *rx_desc_p;
-
- /* get the rx data first */
- rx_desc_p = (struct rx_desc *)ch->desc_base+ch->curr_desc;
- buf = (u8 *)__va(rx_desc_p->data_pointer);
- *(u32 *)dataptr = (u32)buf;
- len = rx_desc_p->status.field.data_length;
-#ifndef CONFIG_MIPS_UNCACHED
- dma_cache_inv((unsigned long)buf, len);
-#endif
- if (opt)
- *(int *)opt = (int)ch->opt[ch->curr_desc];
-
- /* replace with a new allocated buffer */
- buf = dma_dev->buffer_alloc(ch->packet_size, &byte_offset, &p);
- if (buf) {
- ch->opt[ch->curr_desc] = p;
-
- wmb();
- rx_desc_p->data_pointer = (u32)CPHYSADDR((u32)buf);
- rx_desc_p->status.word = (DMA_OWN << 31) \
- |(byte_offset << 23) \
- | ch->packet_size;
-
- wmb();
- } else {
- *(u32 *)dataptr = 0;
- if (opt)
- *(int *)opt = 0;
- }
-
- ch->xfer_cnt++;
- /* increase the curr_desc pointer */
- ch->curr_desc++;
- if (ch->curr_desc == ch->desc_len)
- ch->curr_desc = 0;
- /* return the length of the received packet */
- return len;
-}
-EXPORT_SYMBOL(dma_device_read);
-
-/**
- * Write Packet through DMA Tx channel to peripheral.
- *
- * \param *dma_dev - pointer to DMA device structure
- * \param *dataptr - pointer to data to be sent
- * \param len - amount of data bytes to be sent
- * \param *opt
- * \return len - length of transmitted data
- * \ingroup Internal
- */
-int dma_device_write(struct dma_device_info *dma_dev, u8 *dataptr, int len,
- void *opt)
-{
- unsigned long flag;
- u32 byte_offset;
- struct dma_channel_info *ch;
- int chan_no;
- struct tx_desc *tx_desc_p;
- local_irq_save(flag);
-
- ch = dma_dev->tx_chan[dma_dev->current_tx_chan];
- chan_no = (int)(ch - dma_chan);
-
- if (ch->control == LTQ_DMA_CH_OFF) {
- local_irq_restore(flag);
- printk(KERN_ERR "%s: dma channel %d not enabled!\n",
- __func__, chan_no);
- return 0;
- }
-
- tx_desc_p = (struct tx_desc *)ch->desc_base+ch->curr_desc;
- /* Check whether this descriptor is available */
- if (tx_desc_p->status.word & (DMA_DESC_OWN_DMA | DMA_DESC_CPT_SET)) {
- /* if not , the tell the upper layer device */
- dma_dev->intr_handler(dma_dev, TX_BUF_FULL_INT);
- local_irq_restore(flag);
- return 0;
- }
- ch->opt[ch->curr_desc] = opt;
- /* byte offset----to adjust the starting address of the data buffer,
- * should be multiple of the burst length.*/
- byte_offset = ((u32)CPHYSADDR((u32)dataptr)) %
- (dma_dev->tx_burst_len * 4);
-#ifndef CONFIG_MIPS_UNCACHED
- dma_cache_wback((unsigned long)dataptr, len);
- wmb();
-#endif
- tx_desc_p->data_pointer = (u32)CPHYSADDR((u32)dataptr) - byte_offset;
- wmb();
- tx_desc_p->status.word = (DMA_OWN << 31)
- | DMA_DESC_SOP_SET
- | DMA_DESC_EOP_SET
- | (byte_offset << 23)
- | len;
- wmb();
-
- if (ch->xfer_cnt == 0) {
- mbs_grab();
- dma_w32(chan_no, cs);
- dma_w32_mask(0, DMA_CCTRL_ON_OFF, cctrl);
- mbs_release();
- }
-
- ch->xfer_cnt++;
- ch->curr_desc++;
- if (ch->curr_desc == ch->desc_len)
- ch->curr_desc = 0;
-
- local_irq_restore(flag);
- return len;
-}
-EXPORT_SYMBOL(dma_device_write);
-
-/**
- * Display descriptor list via proc file
- *
- * \param chan_no - logical channel number
- * \ingroup Internal
- */
-int desc_list_proc_read(char *buf, char **start, off_t offset,
- int count, int *eof, void *data)
-{
- int len = 0;
- int i;
- static int chan_no;
- u32 *p;
-
- if ((chan_no == 0) && (offset > count)) {
- *eof = 1;
- return 0;
- }
-
- if (chan_no != 0) {
- *start = buf;
- } else {
- buf = buf + offset;
- *start = buf;
- }
-
- p = (u32 *)dma_chan[chan_no].desc_base;
-
- if (dma_chan[chan_no].dir == DIR_RX)
- len += sprintf(buf + len,
- "channel %d %s Rx descriptor list:\n",
- chan_no, dma_chan[chan_no].dma_dev->device_name);
- else
- len += sprintf(buf + len,
- "channel %d %s Tx descriptor list:\n",
- chan_no, dma_chan[chan_no].dma_dev->device_name);
- len += sprintf(buf + len,
- " no address data pointer command bits "
- "(Own, Complete, SoP, EoP, Offset) \n");
- len += sprintf(buf + len,
- "----------------------------------------------"
- "-----------------------------------\n");
- for (i = 0; i < dma_chan[chan_no].desc_len; i++) {
- len += sprintf(buf + len, "%3d ", i);
- len += sprintf(buf + len, "0x%08x ", (u32)(p + (i * 2)));
- len += sprintf(buf + len, "%08x ", *(p + (i * 2 + 1)));
- len += sprintf(buf + len, "%08x ", *(p + (i * 2)));
-
- if (*(p + (i * 2)) & 0x80000000)
- len += sprintf(buf + len, "D ");
- else
- len += sprintf(buf + len, "C ");
- if (*(p + (i * 2)) & 0x40000000)
- len += sprintf(buf + len, "C ");
- else
- len += sprintf(buf + len, "c ");
- if (*(p + (i * 2)) & 0x20000000)
- len += sprintf(buf + len, "S ");
- else
- len += sprintf(buf + len, "s ");
- if (*(p + (i * 2)) & 0x10000000)
- len += sprintf(buf + len, "E ");
- else
- len += sprintf(buf + len, "e ");
-
- /* byte offset is different for rx and tx descriptors*/
- if (dma_chan[chan_no].dir == DIR_RX) {
- len += sprintf(buf + len, "%01x ",
- (*(p + (i * 2)) & 0x01800000) >> 23);
- } else {
- len += sprintf(buf + len, "%02x ",
- (*(p + (i * 2)) & 0x0F800000) >> 23);
- }
-
- if (dma_chan[chan_no].curr_desc == i)
- len += sprintf(buf + len, "<- CURR");
-
- if (dma_chan[chan_no].prev_desc == i)
- len += sprintf(buf + len, "<- PREV");
-
- len += sprintf(buf + len, "\n");
-
- }
-
- len += sprintf(buf + len, "\n");
- chan_no++;
- if (chan_no > LTQ_MAX_DMA_CHANNEL_NUM - 1)
- chan_no = 0;
-
- *eof = 1;
- return len;
-}
-
-/**
- * Displays the weight of all DMA channels via proc file
- *
- *
- *
- * \param *buf
- * \param **start
- * \param offset
- * \param count
- * \param *eof
- * \param *data
- * \return len - amount of bytes written to file
- */
-int channel_weight_proc_read(char *buf, char **start, off_t offset,
- int count, int *eof, void *data)
-{
- int i;
- int len = 0;
- len += sprintf(buf + len, "Qos dma channel weight list\n");
- len += sprintf(buf + len, "channel_num default_weight "
- "current_weight device Tx/Rx\n");
- len += sprintf(buf + len, "---------------------------"
- "---------------------------------\n");
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++) {
- struct dma_channel_info *ch = &dma_chan[i];
-
- if (ch->dir == DIR_RX) {
- len += sprintf(buf + len,
- " %2d %08x "
- "%08x %10s Rx\n",
- i, ch->default_weight, ch->weight,
- ch->dma_dev->device_name);
- } else {
- len += sprintf(buf + len,
- " %2d %08x "
- "%08x %10s Tx\n",
- i, ch->default_weight, ch->weight,
- ch->dma_dev->device_name);
- }
- }
-
- return len;
-}
-
-/**
- * Provides DMA Register Content to proc file
- * This function reads the content of general DMA Registers, DMA Channel
- * Registers and DMA Port Registers and performs a structures output to the
- * DMA proc file
- *
- * \param *buf
- * \param **start
- * \param offset
- * \param count
- * \param *eof
- * \param *data
- * \return len - amount of bytes written to file
- */
-int dma_register_proc_read(char *buf, char **start, off_t offset,
- int count, int *eof, void *data)
-{
- int len = 0;
- int i;
- int limit = count;
- unsigned long flags;
- static int blockcount;
- static int channel_no;
-
- if ((blockcount == 0) && (offset > count)) {
- *eof = 1;
- return 0;
- }
-
- switch (blockcount) {
- case 0:
- len += sprintf(buf + len, "\nGeneral DMA Registers\n");
- len += sprintf(buf + len, "-------------------------"
- "----------------\n");
- len += sprintf(buf + len, "CLC= %08x\n", dma_r32(clc));
- len += sprintf(buf + len, "ID= %08x\n", dma_r32(id));
- len += sprintf(buf + len, "DMA_CPOLL= %08x\n", dma_r32(cpoll));
- len += sprintf(buf + len, "DMA_CS= %08x\n", dma_r32(cs));
- len += sprintf(buf + len, "DMA_PS= %08x\n", dma_r32(ps));
- len += sprintf(buf + len, "DMA_IRNEN= %08x\n", dma_r32(irnen));
- len += sprintf(buf + len, "DMA_IRNCR= %08x\n", dma_r32(irncr));
- len += sprintf(buf + len, "DMA_IRNICR= %08x\n",
- dma_r32(irnicr));
- len += sprintf(buf + len, "\nDMA Channel Registers\n");
- blockcount = 1;
- return len;
- break;
- case 1:
- /* If we had an overflow start at beginning of buffer
- * otherwise use offset */
- if (channel_no != 0) {
- *start = buf;
- } else {
- buf = buf + offset;
- *start = buf;
- }
-
- local_irq_save(flags);
- for (i = channel_no; i < LTQ_MAX_DMA_CHANNEL_NUM; i++) {
- struct dma_channel_info *ch = &dma_chan[i];
-
- if (len + 300 > limit) {
- local_irq_restore(flags);
- channel_no = i;
- blockcount = 1;
- return len;
- }
- len += sprintf(buf + len, "----------------------"
- "-------------------\n");
- if (ch->dir == DIR_RX) {
- len += sprintf(buf + len,
- "Channel %d - Device %s Rx\n",
- i, ch->dma_dev->device_name);
- } else {
- len += sprintf(buf + len,
- "Channel %d - Device %s Tx\n",
- i, ch->dma_dev->device_name);
- }
- dma_w32(i, cs);
- len += sprintf(buf + len, "DMA_CCTRL= %08x\n",
- dma_r32(cctrl));
- len += sprintf(buf + len, "DMA_CDBA= %08x\n",
- dma_r32(cdba));
- len += sprintf(buf + len, "DMA_CIE= %08x\n",
- dma_r32(cie));
- len += sprintf(buf + len, "DMA_CIS= %08x\n",
- dma_r32(cis));
- len += sprintf(buf + len, "DMA_CDLEN= %08x\n",
- dma_r32(cdlen));
- }
- local_irq_restore(flags);
- blockcount = 2;
- channel_no = 0;
- return len;
- break;
- case 2:
- *start = buf;
- /*
- * display port dependent registers
- */
- len += sprintf(buf + len, "\nDMA Port Registers\n");
- len += sprintf(buf + len,
- "-----------------------------------------\n");
- local_irq_save(flags);
- for (i = 0; i < LTQ_MAX_DMA_DEVICE_NUM; i++) {
- dma_w32(i, ps);
- len += sprintf(buf + len,
- "Port %d DMA_PCTRL= %08x\n",
- i, dma_r32(pctrl));
- }
- local_irq_restore(flags);
- blockcount = 0;
- *eof = 1;
- return len;
- break;
- }
-
- blockcount = 0;
- *eof = 1;
- return 0;
-}
-
-/**
- * Open Method of DMA Device Driver
- * This function increments the device driver's use counter.
- *
- *
- * \param
- * \return
- */
-static int dma_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-/**
- * Release Method of DMA Device driver.
- * This function decrements the device driver's use counter.
- *
- *
- * \param
- * \return
- */
-static int dma_release(struct inode *inode, struct file *file)
-{
- /* release the resources */
- return 0;
-}
-
-/**
- * Ioctl Interface to DMA Module
- *
- * \param None
- * \return 0 - initialization successful
- * <0 - failed initialization
- */
-static long dma_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int result = 0;
- /* TODO: add some user controled functions here */
- return result;
-}
-
-const static struct file_operations dma_fops = {
- .owner = THIS_MODULE,
- .open = dma_open,
- .release = dma_release,
- .unlocked_ioctl = dma_ioctl,
-};
-
-void map_dma_chan(struct dma_channel_info *map)
-{
- int i;
-
- /* assign default values for channel settings */
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++) {
- dma_chan[i].byte_offset = 0;
- dma_chan[i].open = &open_chan;
- dma_chan[i].close = &close_chan;
- dma_chan[i].reset = &reset_chan;
- dma_chan[i].enable_irq = enable_ch_irq;
- dma_chan[i].disable_irq = disable_ch_irq;
- dma_chan[i].tx_weight = 1;
- dma_chan[i].control = 0;
- dma_chan[i].default_weight = LTQ_DMA_CH_DEFAULT_WEIGHT;
- dma_chan[i].weight = dma_chan[i].default_weight;
- dma_chan[i].curr_desc = 0;
- dma_chan[i].prev_desc = 0;
- }
-
- /* assign default values for port settings */
- for (i = 0; i < LTQ_MAX_DMA_DEVICE_NUM; i++) {
- /*set default tx channel number to be one*/
- dma_devices[i].num_tx_chan = 1;
- /*set default rx channel number to be one*/
- dma_devices[i].num_rx_chan = 1;
- dma_devices[i].buffer_alloc = common_buffer_alloc;
- dma_devices[i].buffer_free = common_buffer_free;
- dma_devices[i].intr_handler = NULL;
- dma_devices[i].tx_burst_len = 4;
- dma_devices[i].rx_burst_len = 4;
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
- dma_devices[i].tx_endianness_mode = 0;
- dma_devices[i].rx_endianness_mode = 0;
-#else
- dma_devices[i].tx_endianness_mode = 3;
- dma_devices[i].rx_endianness_mode = 3;
-#endif
- }
-}
-
-void dma_chip_init(void)
-{
- int i;
-
- sys1_w32(SYS1_CLKENR_DMA, clkenr);
- wmb();
- /* reset DMA */
- dma_w32(DMA_CTRL_RST, ctrl);
- wmb();
- /* disable all the interrupts first */
- dma_w32(0, irnen);
-
- /* enable polling for all channels */
- dma_w32(DMA_CPOLL_EN | DMA_CPOLL_CNT_VAL(DMA_POLL_COUNTER), cpoll);
-
- /****************************************************/
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++)
- disable_ch_irq(&dma_chan[i]);
-}
-
-int ltq_dma_init(void)
-{
- int result = 0;
- int i;
- unsigned long flag;
- static int dma_initialized;
-
- if (dma_initialized == 1)
- return 0;
- dma_initialized = 1;
-
- result = register_chrdev(DMA_MAJOR, "dma-core", &dma_fops);
- if (result) {
- DMA_EMSG("cannot register device dma-core!\n");
- return result;
- }
-
- dma_chip_init();
- map_dma_chan(dma_chan);
-
- /* allocate DMA memory for buffer descriptors */
- for (i = 0; i < DMA_DESCR_MEM_PAGES; i++) {
- g_desc_list[i] = (u64 *)__get_free_page(GFP_DMA);
- if (g_desc_list[i] == NULL) {
- DMA_EMSG("no memory for desriptor\n");
- return -ENOMEM;
- }
- g_desc_list[i] = (u64 *)KSEG1ADDR(g_desc_list[i]);
- memset(g_desc_list[i], 0, PAGE_SIZE);
- }
-
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++) {
- int page_index, ch_per_page;
- /* cross-link relative channels of a port to
- * corresponding absolute channels */
- if (dma_chan[i].dir == DIR_RX) {
- ((struct dma_device_info *)(dma_chan[i].dma_dev))->
- rx_chan[dma_chan[i].rel_chan_no] = &dma_chan[i];
- } else {
- ((struct dma_device_info *)(dma_chan[i].dma_dev))->
- tx_chan[dma_chan[i].rel_chan_no] = &dma_chan[i];
- }
- dma_chan[i].abs_chan_no = i;
-
- page_index = i * DMA_DESCR_CH_SIZE / PAGE_SIZE;
- ch_per_page = PAGE_SIZE / DMA_DESCR_CH_SIZE +
- ((PAGE_SIZE % DMA_DESCR_CH_SIZE) > 0);
- dma_chan[i].desc_base =
- (u32)g_desc_list[page_index] +
- (i - page_index*ch_per_page) * DMA_DESCR_NUM*8;
- dma_chan[i].curr_desc = 0;
- dma_chan[i].desc_len = DMA_DESCR_NUM;
-
- local_irq_save(flag);
- mbs_grab();
- dma_w32(i, cs);
- dma_w32((u32)CPHYSADDR(dma_chan[i].desc_base), cdba);
- mbs_release();
- local_irq_restore(flag);
- }
-
- g_dma_dir = proc_mkdir("driver/" DRV_NAME, NULL);
-
- create_proc_read_entry("dma_register",
- 0,
- g_dma_dir,
- dma_register_proc_read,
- NULL);
-
- create_proc_read_entry("g_desc_list",
- 0,
- g_dma_dir,
- desc_list_proc_read,
- NULL);
-
- create_proc_read_entry("channel_weight",
- 0,
- g_dma_dir,
- channel_weight_proc_read,
- NULL);
-
- printk(KERN_NOTICE "SVIP DMA engine initialized\n");
-
- return 0;
-}
-
-/**
- * Cleanup DMA device
- * This function releases all resources used by the DMA device driver on
- * module removal.
- *
- *
- * \param None
- * \return Nothing
- */
-void dma_cleanup(void)
-{
- int i;
- unregister_chrdev(DMA_MAJOR, "dma-core");
-
- for (i = 0; i < DMA_DESCR_MEM_PAGES; i++)
- free_page(KSEG0ADDR((unsigned long)g_desc_list[i]));
- remove_proc_entry("channel_weight", g_dma_dir);
- remove_proc_entry("g_desc_list", g_dma_dir);
- remove_proc_entry("dma_register", g_dma_dir);
- remove_proc_entry("driver/" DRV_NAME, NULL);
- /* release the resources */
- for (i = 0; i < LTQ_MAX_DMA_CHANNEL_NUM; i++)
- free_irq(dma_chan[i].irq, (void *)&dma_chan[i]);
-}
-
-arch_initcall(ltq_dma_init);
-
-MODULE_LICENSE("GPL");