diff options
Diffstat (limited to 'drivers/net/wan/pc300_drv.c')
-rw-r--r-- | drivers/net/wan/pc300_drv.c | 3670 |
1 files changed, 0 insertions, 3670 deletions
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c deleted file mode 100644 index cb0f8d932b0..00000000000 --- a/drivers/net/wan/pc300_drv.c +++ /dev/null @@ -1,3670 +0,0 @@ -#define USE_PCI_CLOCK -static const char rcsid[] = -"Revision: 3.4.5 Date: 2002/03/07 "; - -/* - * pc300.c Cyclades-PC300(tm) Driver. - * - * Author: Ivan Passos <ivan@cyclades.com> - * Maintainer: PC300 Maintainer <pc300@cyclades.com> - * - * Copyright: (c) 1999-2003 Cyclades Corp. - * - * 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. - * - * Using tabstop = 4. - * - * $Log: pc300_drv.c,v $ - * Revision 3.23 2002/03/20 13:58:40 henrique - * Fixed ortographic mistakes - * - * Revision 3.22 2002/03/13 16:56:56 henrique - * Take out the debug messages - * - * Revision 3.21 2002/03/07 14:17:09 henrique - * License data fixed - * - * Revision 3.20 2002/01/17 17:58:52 ivan - * Support for PC300-TE/M (PMC). - * - * Revision 3.19 2002/01/03 17:08:47 daniela - * Enables DMA reception when the SCA-II disables it improperly. - * - * Revision 3.18 2001/12/03 18:47:50 daniela - * Esthetic changes. - * - * Revision 3.17 2001/10/19 16:50:13 henrique - * Patch to kernel 2.4.12 and new generic hdlc. - * - * Revision 3.16 2001/10/16 15:12:31 regina - * clear statistics - * - * Revision 3.11 to 3.15 2001/10/11 20:26:04 daniela - * More DMA fixes for noisy lines. - * Return the size of bad frames in dma_get_rx_frame_size, so that the Rx buffer - * descriptors can be cleaned by dma_buf_read (called in cpc_net_rx). - * Renamed dma_start routine to rx_dma_start. Improved Rx statistics. - * Fixed BOF interrupt treatment. Created dma_start routine. - * Changed min and max to cpc_min and cpc_max. - * - * Revision 3.10 2001/08/06 12:01:51 regina - * Fixed problem in DSR_DE bit. - * - * Revision 3.9 2001/07/18 19:27:26 daniela - * Added some history comments. - * - * Revision 3.8 2001/07/12 13:11:19 regina - * bug fix - DCD-OFF in pc300 tty driver - * - * Revision 3.3 to 3.7 2001/07/06 15:00:20 daniela - * Removing kernel 2.4.3 and previous support. - * DMA transmission bug fix. - * MTU check in cpc_net_rx fixed. - * Boot messages reviewed. - * New configuration parameters (line code, CRC calculation and clock). - * - * Revision 3.2 2001/06/22 13:13:02 regina - * MLPPP implementation. Changed the header of message trace to include - * the device name. New format : "hdlcX[R/T]: ". - * Default configuration changed. - * - * Revision 3.1 2001/06/15 regina - * in cpc_queue_xmit, netif_stop_queue is called if don't have free descriptor - * upping major version number - * - * Revision 1.1.1.1 2001/06/13 20:25:04 daniela - * PC300 initial CVS version (3.4.0-pre1) - * - * Revision 3.0.1.2 2001/06/08 daniela - * Did some changes in the DMA programming implementation to avoid the - * occurrence of a SCA-II bug when CDA is accessed during a DMA transfer. - * - * Revision 3.0.1.1 2001/05/02 daniela - * Added kernel 2.4.3 support. - * - * Revision 3.0.1.0 2001/03/13 daniela, henrique - * Added Frame Relay Support. - * Driver now uses HDLC generic driver to provide protocol support. - * - * Revision 3.0.0.8 2001/03/02 daniela - * Fixed ram size detection. - * Changed SIOCGPC300CONF ioctl, to give hw information to pc300util. - * - * Revision 3.0.0.7 2001/02/23 daniela - * netif_stop_queue called before the SCA-II transmition commands in - * cpc_queue_xmit, and with interrupts disabled to avoid race conditions with - * transmition interrupts. - * Fixed falc_check_status for Unframed E1. - * - * Revision 3.0.0.6 2000/12/13 daniela - * Implemented pc300util support: trace, statistics, status and loopback - * tests for the PC300 TE boards. - * - * Revision 3.0.0.5 2000/12/12 ivan - * Added support for Unframed E1. - * Implemented monitor mode. - * Fixed DCD sensitivity on the second channel. - * Driver now complies with new PCI kernel architecture. - * - * Revision 3.0.0.4 2000/09/28 ivan - * Implemented DCD sensitivity. - * Moved hardware-specific open to the end of cpc_open, to avoid race - * conditions with early reception interrupts. - * Included code for [request|release]_mem_region(). - * Changed location of pc300.h . - * Minor code revision (contrib. of Jeff Garzik). - * - * Revision 3.0.0.3 2000/07/03 ivan - * Previous bugfix for the framing errors with external clock made X21 - * boards stop working. This version fixes it. - * - * Revision 3.0.0.2 2000/06/23 ivan - * Revisited cpc_queue_xmit to prevent race conditions on Tx DMA buffer - * handling when Tx timeouts occur. - * Revisited Rx statistics. - * Fixed a bug in the SCA-II programming that would cause framing errors - * when external clock was configured. - * - * Revision 3.0.0.1 2000/05/26 ivan - * Added logic in the SCA interrupt handler so that no board can monopolize - * the driver. - * Request PLX I/O region, although driver doesn't use it, to avoid - * problems with other drivers accessing it. - * - * Revision 3.0.0.0 2000/05/15 ivan - * Did some changes in the DMA programming implementation to avoid the - * occurrence of a SCA-II bug in the second channel. - * Implemented workaround for PLX9050 bug that would cause a system lockup - * in certain systems, depending on the MMIO addresses allocated to the - * board. - * Fixed the FALC chip programming to avoid synchronization problems in the - * second channel (TE only). - * Implemented a cleaner and faster Tx DMA descriptor cleanup procedure in - * cpc_queue_xmit(). - * Changed the built-in driver implementation so that the driver can use the - * general 'hdlcN' naming convention instead of proprietary device names. - * Driver load messages are now device-centric, instead of board-centric. - * Dynamic allocation of net_device structures. - * Code is now compliant with the new module interface (module_[init|exit]). - * Make use of the PCI helper functions to access PCI resources. - * - * Revision 2.0.0.0 2000/04/15 ivan - * Added support for the PC300/TE boards (T1/FT1/E1/FE1). - * - * Revision 1.1.0.0 2000/02/28 ivan - * Major changes in the driver architecture. - * Softnet compliancy implemented. - * Driver now reports physical instead of virtual memory addresses. - * Added cpc_change_mtu function. - * - * Revision 1.0.0.0 1999/12/16 ivan - * First official release. - * Support for 1- and 2-channel boards (which use distinct PCI Device ID's). - * Support for monolythic installation (i.e., drv built into the kernel). - * X.25 additional checking when lapb_[dis]connect_request returns an error. - * SCA programming now covers X.21 as well. - * - * Revision 0.3.1.0 1999/11/18 ivan - * Made X.25 support configuration-dependent (as it depends on external - * modules to work). - * Changed X.25-specific function names to comply with adopted convention. - * Fixed typos in X.25 functions that would cause compile errors (Daniela). - * Fixed bug in ch_config that would disable interrupts on a previously - * enabled channel if the other channel on the same board was enabled later. - * - * Revision 0.3.0.0 1999/11/16 daniela - * X.25 support. - * - * Revision 0.2.3.0 1999/11/15 ivan - * Function cpc_ch_status now provides more detailed information. - * Added support for X.21 clock configuration. - * Changed TNR1 setting in order to prevent Tx FIFO overaccesses by the SCA. - * Now using PCI clock instead of internal oscillator clock for the SCA. - * - * Revision 0.2.2.0 1999/11/10 ivan - * Changed the *_dma_buf_check functions so that they would print only - * the useful info instead of the whole buffer descriptor bank. - * Fixed bug in cpc_queue_xmit that would eventually crash the system - * in case of a packet drop. - * Implemented TX underrun handling. - * Improved SCA fine tuning to boost up its performance. - * - * Revision 0.2.1.0 1999/11/03 ivan - * Added functions *dma_buf_pt_init to allow independent initialization - * of the next-descr. and DMA buffer pointers on the DMA descriptors. - * Kernel buffer release and tbusy clearing is now done in the interrupt - * handler. - * Fixed bug in cpc_open that would cause an interface reopen to fail. - * Added a protocol-specific code section in cpc_net_rx. - * Removed printk level defs (they might be added back after the beta phase). - * - * Revision 0.2.0.0 1999/10/28 ivan - * Revisited the code so that new protocols can be easily added / supported. - * - * Revision 0.1.0.1 1999/10/20 ivan - * Mostly "esthetic" changes. - * - * Revision 0.1.0.0 1999/10/11 ivan - * Initial version. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/net.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/spinlock.h> -#include <linux/if.h> -#include <linux/slab.h> -#include <net/arp.h> - -#include <asm/io.h> -#include <asm/uaccess.h> - -#include "pc300.h" - -#define CPC_LOCK(card,flags) \ - do { \ - spin_lock_irqsave(&card->card_lock, flags); \ - } while (0) - -#define CPC_UNLOCK(card,flags) \ - do { \ - spin_unlock_irqrestore(&card->card_lock, flags); \ - } while (0) - -#undef PC300_DEBUG_PCI -#undef PC300_DEBUG_INTR -#undef PC300_DEBUG_TX -#undef PC300_DEBUG_RX -#undef PC300_DEBUG_OTHER - -static DEFINE_PCI_DEVICE_TABLE(cpc_pci_dev_id) = { - /* PC300/RSV or PC300/X21, 2 chan */ - {0x120e, 0x300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x300}, - /* PC300/RSV or PC300/X21, 1 chan */ - {0x120e, 0x301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x301}, - /* PC300/TE, 2 chan */ - {0x120e, 0x310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x310}, - /* PC300/TE, 1 chan */ - {0x120e, 0x311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x311}, - /* PC300/TE-M, 2 chan */ - {0x120e, 0x320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x320}, - /* PC300/TE-M, 1 chan */ - {0x120e, 0x321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x321}, - /* End of table */ - {0,}, -}; -MODULE_DEVICE_TABLE(pci, cpc_pci_dev_id); - -#ifndef cpc_min -#define cpc_min(a,b) (((a)<(b))?(a):(b)) -#endif -#ifndef cpc_max -#define cpc_max(a,b) (((a)>(b))?(a):(b)) -#endif - -/* prototypes */ -static void tx_dma_buf_pt_init(pc300_t *, int); -static void tx_dma_buf_init(pc300_t *, int); -static void rx_dma_buf_pt_init(pc300_t *, int); -static void rx_dma_buf_init(pc300_t *, int); -static void tx_dma_buf_check(pc300_t *, int); -static void rx_dma_buf_check(pc300_t *, int); -static irqreturn_t cpc_intr(int, void *); -static int clock_rate_calc(u32, u32, int *); -static u32 detect_ram(pc300_t *); -static void plx_init(pc300_t *); -static void cpc_trace(struct net_device *, struct sk_buff *, char); -static int cpc_attach(struct net_device *, unsigned short, unsigned short); -static int cpc_close(struct net_device *dev); - -#ifdef CONFIG_PC300_MLPPP -void cpc_tty_init(pc300dev_t * dev); -void cpc_tty_unregister_service(pc300dev_t * pc300dev); -void cpc_tty_receive(pc300dev_t * pc300dev); -void cpc_tty_trigger_poll(pc300dev_t * pc300dev); -#endif - -/************************/ -/*** DMA Routines ***/ -/************************/ -static void tx_dma_buf_pt_init(pc300_t * card, int ch) -{ - int i; - int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase - + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); - - for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { - cpc_writel(&ptdescr->next, (u32)(DMA_TX_BD_BASE + - (ch_factor + ((i + 1) & (N_DMA_TX_BUF - 1))) * sizeof(pcsca_bd_t))); - cpc_writel(&ptdescr->ptbuf, - (u32)(DMA_TX_BASE + (ch_factor + i) * BD_DEF_LEN)); - } -} - -static void tx_dma_buf_init(pc300_t * card, int ch) -{ - int i; - int ch_factor = ch * N_DMA_TX_BUF; - volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase - + DMA_TX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); - - for (i = 0; i < N_DMA_TX_BUF; i++, ptdescr++) { - memset_io(ptdescr, 0, sizeof(pcsca_bd_t)); - cpc_writew(&ptdescr->len, 0); - cpc_writeb(&ptdescr->status, DST_OSB); - } - tx_dma_buf_pt_init(card, ch); -} - -static void rx_dma_buf_pt_init(pc300_t * card, int ch) -{ - int i; - int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase - + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); - - for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { - cpc_writel(&ptdescr->next, (u32)(DMA_RX_BD_BASE + - (ch_factor + ((i + 1) & (N_DMA_RX_BUF - 1))) * sizeof(pcsca_bd_t))); - cpc_writel(&ptdescr->ptbuf, - (u32)(DMA_RX_BASE + (ch_factor + i) * BD_DEF_LEN)); - } -} - -static void rx_dma_buf_init(pc300_t * card, int ch) -{ - int i; - int ch_factor = ch * N_DMA_RX_BUF; - volatile pcsca_bd_t __iomem *ptdescr = (card->hw.rambase - + DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); - - for (i = 0; i < N_DMA_RX_BUF; i++, ptdescr++) { - memset_io(ptdescr, 0, sizeof(pcsca_bd_t)); - cpc_writew(&ptdescr->len, 0); - cpc_writeb(&ptdescr->status, 0); - } - rx_dma_buf_pt_init(card, ch); -} - -static void tx_dma_buf_check(pc300_t * card, int ch) -{ - volatile pcsca_bd_t __iomem *ptdescr; - int i; - u16 first_bd = card->chan[ch].tx_first_bd; - u16 next_bd = card->chan[ch].tx_next_bd; - - printk("#CH%d: f_bd = %d(0x%08zx), n_bd = %d(0x%08zx)\n", ch, - first_bd, TX_BD_ADDR(ch, first_bd), - next_bd, TX_BD_ADDR(ch, next_bd)); - for (i = first_bd, - ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, first_bd)); - i != ((next_bd + 1) & (N_DMA_TX_BUF - 1)); - i = (i + 1) & (N_DMA_TX_BUF - 1), - ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i))) { - printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d", - ch, i, cpc_readl(&ptdescr->next), - cpc_readl(&ptdescr->ptbuf), - cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len)); - } - printk("\n"); -} - -#ifdef PC300_DEBUG_OTHER -/* Show all TX buffer descriptors */ -static void tx1_dma_buf_check(pc300_t * card, int ch) -{ - volatile pcsca_bd_t __iomem *ptdescr; - int i; - u16 first_bd = card->chan[ch].tx_first_bd; - u16 next_bd = card->chan[ch].tx_next_bd; - u32 scabase = card->hw.scabase; - - printk ("\nnfree_tx_bd = %d\n", card->chan[ch].nfree_tx_bd); - printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch, - first_bd, TX_BD_ADDR(ch, first_bd), - next_bd, TX_BD_ADDR(ch, next_bd)); - printk("TX_CDA=0x%08x, TX_EDA=0x%08x\n", - cpc_readl(scabase + DTX_REG(CDAL, ch)), - cpc_readl(scabase + DTX_REG(EDAL, ch))); - for (i = 0; i < N_DMA_TX_BUF; i++) { - ptdescr = (card->hw.rambase + TX_BD_ADDR(ch, i)); - printk("\n CH%d TX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d", - ch, i, cpc_readl(&ptdescr->next), - cpc_readl(&ptdescr->ptbuf), - cpc_readb(&ptdescr->status), cpc_readw(&ptdescr->len)); - } - printk("\n"); -} -#endif - -static void rx_dma_buf_check(pc300_t * card, int ch) -{ - volatile pcsca_bd_t __iomem *ptdescr; - int i; - u16 first_bd = card->chan[ch].rx_first_bd; - u16 last_bd = card->chan[ch].rx_last_bd; - int ch_factor; - - ch_factor = ch * N_DMA_RX_BUF; - printk("#CH%d: f_bd = %d, l_bd = %d\n", ch, first_bd, last_bd); - for (i = 0, ptdescr = (card->hw.rambase + - DMA_RX_BD_BASE + ch_factor * sizeof(pcsca_bd_t)); - i < N_DMA_RX_BUF; i++, ptdescr++) { - if (cpc_readb(&ptdescr->status) & DST_OSB) - printk ("\n CH%d RX%d: next=0x%x, ptbuf=0x%x, ST=0x%x, len=%d", - ch, i, cpc_readl(&ptdescr->next), - cpc_readl(&ptdescr->ptbuf), - cpc_readb(&ptdescr->status), - cpc_readw(&ptdescr->len)); - } - printk("\n"); -} - -static int dma_get_rx_frame_size(pc300_t * card, int ch) -{ - volatile pcsca_bd_t __iomem *ptdescr; - u16 first_bd = card->chan[ch].rx_first_bd; - int rcvd = 0; - volatile u8 status; - - ptdescr = (card->hw.rambase + RX_BD_ADDR(ch, first_bd)); - while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { - rcvd += cpc_readw(&ptdescr->len); - first_bd = (first_bd + 1) & (N_DMA_RX_BUF - 1); - if ((status & DST_EOM) || (first_bd == card->chan[ch].rx_last_bd)) { - /* Return the size of a good frame or incomplete bad frame - * (dma_buf_read will clean the buffer descriptors in this case). */ - return rcvd; - } - ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); - } - return -1; -} - -/* - * dma_buf_write: writes a frame to the Tx DMA buffers - * NOTE: this function writes one frame at a time. - */ -static int dma_buf_write(pc300_t *card, int ch, u8 *ptdata, int len) -{ - int i, nchar; - volatile pcsca_bd_t __iomem *ptdescr; - int tosend = len; - u8 nbuf = ((len - 1) / BD_DEF_LEN) + 1; - - if (nbuf >= card->chan[ch].nfree_tx_bd) { - return -ENOMEM; - } - - for (i = 0; i < nbuf; i++) { - ptdescr = (card->hw.rambase + - TX_BD_ADDR(ch, card->chan[ch].tx_next_bd)); - nchar = cpc_min(BD_DEF_LEN, tosend); - if (cpc_readb(&ptdescr->status) & DST_OSB) { - memcpy_toio((card->hw.rambase + cpc_readl(&ptdescr->ptbuf)), - &ptdata[len - tosend], nchar); - cpc_writew(&ptdescr->len, nchar); - card->chan[ch].nfree_tx_bd--; - if ((i + 1) == nbuf) { - /* This must be the last BD to be used */ - cpc_writeb(&ptdescr->status, DST_EOM); - } else { - cpc_writeb(&ptdescr->status, 0); - } - } else { - return -ENOMEM; - } - tosend -= nchar; - card->chan[ch].tx_next_bd = - (card->chan[ch].tx_next_bd + 1) & (N_DMA_TX_BUF - 1); - } - /* If it gets to here, it means we have sent the whole frame */ - return 0; -} - -/* - * dma_buf_read: reads a frame from the Rx DMA buffers - * NOTE: this function reads one frame at a time. - */ -static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) -{ - int nchar; - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - volatile pcsca_bd_t __iomem *ptdescr; - int rcvd = 0; - volatile u8 status; - - ptdescr = (card->hw.rambase + - RX_BD_ADDR(ch, chan->rx_first_bd)); - while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { - nchar = cpc_readw(&ptdescr->len); - if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) || - (nchar > BD_DEF_LEN)) { - - if (nchar > BD_DEF_LEN) - status |= DST_RBIT; - rcvd = -status; - /* Discard remaining descriptors used by the bad frame */ - while (chan->rx_first_bd != chan->rx_last_bd) { - cpc_writeb(&ptdescr->status, 0); - chan->rx_first_bd = (chan->rx_first_bd+1) & (N_DMA_RX_BUF-1); - if (status & DST_EOM) - break; - ptdescr = (card->hw.rambase + - cpc_readl(&ptdescr->next)); - status = cpc_readb(&ptdescr->status); - } - break; - } - if (nchar != 0) { - if (skb) { - memcpy_fromio(skb_put(skb, nchar), - (card->hw.rambase+cpc_readl(&ptdescr->ptbuf)),nchar); - } - rcvd += nchar; - } - cpc_writeb(&ptdescr->status, 0); - cpc_writeb(&ptdescr->len, 0); - chan->rx_first_bd = (chan->rx_first_bd + 1) & (N_DMA_RX_BUF - 1); - - if (status & DST_EOM) - break; - - ptdescr = (card->hw.rambase + cpc_readl(&ptdescr->next)); - } - - if (rcvd != 0) { - /* Update pointer */ - chan->rx_last_bd = (chan->rx_first_bd - 1) & (N_DMA_RX_BUF - 1); - /* Update EDA */ - cpc_writel(card->hw.scabase + DRX_REG(EDAL, ch), - RX_BD_ADDR(ch, chan->rx_last_bd)); - } - return rcvd; -} - -static void tx_dma_stop(pc300_t * card, int ch) -{ - void __iomem *scabase = card->hw.scabase; - u8 drr_ena_bit = 1 << (5 + 2 * ch); - u8 drr_rst_bit = 1 << (1 + 2 * ch); - - /* Disable DMA */ - cpc_writeb(scabase + DRR, drr_ena_bit); - cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); -} - -static void rx_dma_stop(pc300_t * card, int ch) -{ - void __iomem *scabase = card->hw.scabase; - u8 drr_ena_bit = 1 << (4 + 2 * ch); - u8 drr_rst_bit = 1 << (2 * ch); - - /* Disable DMA */ - cpc_writeb(scabase + DRR, drr_ena_bit); - cpc_writeb(scabase + DRR, drr_rst_bit & ~drr_ena_bit); -} - -static void rx_dma_start(pc300_t * card, int ch) -{ - void __iomem *scabase = card->hw.scabase; - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - - /* Start DMA */ - cpc_writel(scabase + DRX_REG(CDAL, ch), - RX_BD_ADDR(ch, chan->rx_first_bd)); - if (cpc_readl(scabase + DRX_REG(CDAL,ch)) != - RX_BD_ADDR(ch, chan->rx_first_bd)) { - cpc_writel(scabase + DRX_REG(CDAL, ch), - RX_BD_ADDR(ch, chan->rx_first_bd)); - } - cpc_writel(scabase + DRX_REG(EDAL, ch), - RX_BD_ADDR(ch, chan->rx_last_bd)); - cpc_writew(scabase + DRX_REG(BFLL, ch), BD_DEF_LEN); - cpc_writeb(scabase + DSR_RX(ch), DSR_DE); - if (!(cpc_readb(scabase + DSR_RX(ch)) & DSR_DE)) { - cpc_writeb(scabase + DSR_RX(ch), DSR_DE); - } -} - -/*************************/ -/*** FALC Routines ***/ -/*************************/ -static void falc_issue_cmd(pc300_t *card, int ch, u8 cmd) -{ - void __iomem *falcbase = card->hw.falcbase; - unsigned long i = 0; - - while (cpc_readb(falcbase + F_REG(SIS, ch)) & SIS_CEC) { - if (i++ >= PC300_FALC_MAXLOOP) { - printk("%s: FALC command locked(cmd=0x%x).\n", - card->chan[ch].d.name, cmd); - break; - } - } - cpc_writeb(falcbase + F_REG(CMDR, ch), cmd); -} - -static void falc_intr_enable(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - falc_t *pfalc = (falc_t *) & chan->falc; - void __iomem *falcbase = card->hw.falcbase; - - /* Interrupt pins are open-drain */ - cpc_writeb(falcbase + F_REG(IPC, ch), - cpc_readb(falcbase + F_REG(IPC, ch)) & ~IPC_IC0); - /* Conters updated each second */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_ECM); - /* Enable SEC and ES interrupts */ - cpc_writeb(falcbase + F_REG(IMR3, ch), - cpc_readb(falcbase + F_REG(IMR3, ch)) & ~(IMR3_SEC | IMR3_ES)); - if (conf->fr_mode == PC300_FR_UNFRAMED) { - cpc_writeb(falcbase + F_REG(IMR4, ch), - cpc_readb(falcbase + F_REG(IMR4, ch)) & ~(IMR4_LOS)); - } else { - cpc_writeb(falcbase + F_REG(IMR4, ch), - cpc_readb(falcbase + F_REG(IMR4, ch)) & - ~(IMR4_LFA | IMR4_AIS | IMR4_LOS | IMR4_SLIP)); - } - if (conf->media == IF_IFACE_T1) { - cpc_writeb(falcbase + F_REG(IMR3, ch), - cpc_readb(falcbase + F_REG(IMR3, ch)) & ~IMR3_LLBSC); - } else { - cpc_writeb(falcbase + F_REG(IPC, ch), - cpc_readb(falcbase + F_REG(IPC, ch)) | IPC_SCI); - if (conf->fr_mode == PC300_FR_UNFRAMED) { - cpc_writeb(falcbase + F_REG(IMR2, ch), - cpc_readb(falcbase + F_REG(IMR2, ch)) & ~(IMR2_LOS)); - } else { - cpc_writeb(falcbase + F_REG(IMR2, ch), - cpc_readb(falcbase + F_REG(IMR2, ch)) & - ~(IMR2_FAR | IMR2_LFA | IMR2_AIS | IMR2_LOS)); - if (pfalc->multiframe_mode) { - cpc_writeb(falcbase + F_REG(IMR2, ch), - cpc_readb(falcbase + F_REG(IMR2, ch)) & - ~(IMR2_T400MS | IMR2_MFAR)); - } else { - cpc_writeb(falcbase + F_REG(IMR2, ch), - cpc_readb(falcbase + F_REG(IMR2, ch)) | - IMR2_T400MS | IMR2_MFAR); - } - } - } -} - -static void falc_open_timeslot(pc300_t * card, int ch, int timeslot) -{ - void __iomem *falcbase = card->hw.falcbase; - u8 tshf = card->chan[ch].falc.offset; - - cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), - cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) & - ~(0x80 >> ((timeslot - tshf) & 0x07))); - cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch), - cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) | - (0x80 >> (timeslot & 0x07))); - cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch), - cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) | - (0x80 >> (timeslot & 0x07))); -} - -static void falc_close_timeslot(pc300_t * card, int ch, int timeslot) -{ - void __iomem *falcbase = card->hw.falcbase; - u8 tshf = card->chan[ch].falc.offset; - - cpc_writeb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch), - cpc_readb(falcbase + F_REG((ICB1 + (timeslot - tshf) / 8), ch)) | - (0x80 >> ((timeslot - tshf) & 0x07))); - cpc_writeb(falcbase + F_REG((TTR1 + timeslot / 8), ch), - cpc_readb(falcbase + F_REG((TTR1 + timeslot / 8), ch)) & - ~(0x80 >> (timeslot & 0x07))); - cpc_writeb(falcbase + F_REG((RTR1 + timeslot / 8), ch), - cpc_readb(falcbase + F_REG((RTR1 + timeslot / 8), ch)) & - ~(0x80 >> (timeslot & 0x07))); -} - -static void falc_close_all_timeslots(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - void __iomem *falcbase = card->hw.falcbase; - - cpc_writeb(falcbase + F_REG(ICB1, ch), 0xff); - cpc_writeb(falcbase + F_REG(TTR1, ch), 0); - cpc_writeb(falcbase + F_REG(RTR1, ch), 0); - cpc_writeb(falcbase + F_REG(ICB2, ch), 0xff); - cpc_writeb(falcbase + F_REG(TTR2, ch), 0); - cpc_writeb(falcbase + F_REG(RTR2, ch), 0); - cpc_writeb(falcbase + F_REG(ICB3, ch), 0xff); - cpc_writeb(falcbase + F_REG(TTR3, ch), 0); - cpc_writeb(falcbase + F_REG(RTR3, ch), 0); - if (conf->media == IF_IFACE_E1) { - cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff); - cpc_writeb(falcbase + F_REG(TTR4, ch), 0); - cpc_writeb(falcbase + F_REG(RTR4, ch), 0); - } -} - -static void falc_open_all_timeslots(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - void __iomem *falcbase = card->hw.falcbase; - - cpc_writeb(falcbase + F_REG(ICB1, ch), 0); - if (conf->fr_mode == PC300_FR_UNFRAMED) { - cpc_writeb(falcbase + F_REG(TTR1, ch), 0xff); - cpc_writeb(falcbase + F_REG(RTR1, ch), 0xff); - } else { - /* Timeslot 0 is never enabled */ - cpc_writeb(falcbase + F_REG(TTR1, ch), 0x7f); - cpc_writeb(falcbase + F_REG(RTR1, ch), 0x7f); - } - cpc_writeb(falcbase + F_REG(ICB2, ch), 0); - cpc_writeb(falcbase + F_REG(TTR2, ch), 0xff); - cpc_writeb(falcbase + F_REG(RTR2, ch), 0xff); - cpc_writeb(falcbase + F_REG(ICB3, ch), 0); - cpc_writeb(falcbase + F_REG(TTR3, ch), 0xff); - cpc_writeb(falcbase + F_REG(RTR3, ch), 0xff); - if (conf->media == IF_IFACE_E1) { - cpc_writeb(falcbase + F_REG(ICB4, ch), 0); - cpc_writeb(falcbase + F_REG(TTR4, ch), 0xff); - cpc_writeb(falcbase + F_REG(RTR4, ch), 0xff); - } else { - cpc_writeb(falcbase + F_REG(ICB4, ch), 0xff); - cpc_writeb(falcbase + F_REG(TTR4, ch), 0x80); - cpc_writeb(falcbase + F_REG(RTR4, ch), 0x80); - } -} - -static void falc_init_timeslot(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - falc_t *pfalc = (falc_t *) & chan->falc; - int tslot; - - for (tslot = 0; tslot < pfalc->num_channels; tslot++) { - if (conf->tslot_bitmap & (1 << tslot)) { - // Channel enabled - falc_open_timeslot(card, ch, tslot + 1); - } else { - // Channel disabled - falc_close_timeslot(card, ch, tslot + 1); - } - } -} - -static void falc_enable_comm(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - falc_t *pfalc = (falc_t *) & chan->falc; - - if (pfalc->full_bandwidth) { - falc_open_all_timeslots(card, ch); - } else { - falc_init_timeslot(card, ch); - } - // CTS/DCD ON - cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1, - cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) & - ~((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); -} - -static void falc_disable_comm(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - falc_t *pfalc = (falc_t *) & chan->falc; - - if (pfalc->loop_active != 2) { - falc_close_all_timeslots(card, ch); - } - // CTS/DCD OFF - cpc_writeb(card->hw.falcbase + card->hw.cpld_reg1, - cpc_readb(card->hw.falcbase + card->hw.cpld_reg1) | - ((CPLD_REG1_FALC_DCD | CPLD_REG1_FALC_CTS) << (2 * ch))); -} - -static void falc_init_t1(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - falc_t *pfalc = (falc_t *) & chan->falc; - void __iomem *falcbase = card->hw.falcbase; - u8 dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); - - /* Switch to T1 mode (PCM 24) */ - cpc_writeb(falcbase + F_REG(FMR1, ch), FMR1_PMOD); - - /* Wait 20 us for setup */ - udelay(20); - - /* Transmit Buffer Size (1 frame) */ - cpc_writeb(falcbase + F_REG(SIC1, ch), SIC1_XBS0); - - /* Clock mode */ - if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */ - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS); - } else { /* Slave mode */ - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS); - cpc_writeb(falcbase + F_REG(LOOP, ch), - cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_RTM); - } - - cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI); - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) & - ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1)); - - switch (conf->lcode) { - case PC300_LC_AMI: - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | - FMR0_XC1 | FMR0_RC1); - /* Clear Channel register to ON for all channels */ - cpc_writeb(falcbase + F_REG(CCB1, ch), 0xff); - cpc_writeb(falcbase + F_REG(CCB2, ch), 0xff); - cpc_writeb(falcbase + F_REG(CCB3, ch), 0xff); - break; - - case PC300_LC_B8ZS: - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | - FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1); - break; - - case PC300_LC_NRZ: - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | 0x00); - break; - } - - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_ELOS); - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0)); - /* Set interface mode to 2 MBPS */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD); - - switch (conf->fr_mode) { - case PC300_FR_ESF: - pfalc->multiframe_mode = 0; - cpc_writeb(falcbase + F_REG(FMR4, ch), - cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_FM1); - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | - FMR1_CRC | FMR1_EDL); - cpc_writeb(falcbase + F_REG(XDL1, ch), 0); - cpc_writeb(falcbase + F_REG(XDL2, ch), 0); - cpc_writeb(falcbase + F_REG(XDL3, ch), 0); - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) & ~FMR0_SRAF); - cpc_writeb(falcbase + F_REG(FMR2, ch), - cpc_readb(falcbase + F_REG(FMR2,ch)) | FMR2_MCSP | FMR2_SSP); - break; - - case PC300_FR_D4: - pfalc->multiframe_mode = 1; - cpc_writeb(falcbase + F_REG(FMR4, ch), - cpc_readb(falcbase + F_REG(FMR4, ch)) & - ~(FMR4_FM1 | FMR4_FM0)); - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | FMR0_SRAF); - cpc_writeb(falcbase + F_REG(FMR2, ch), - cpc_readb(falcbase + F_REG(FMR2, ch)) & ~FMR2_SSP); - break; - } - - /* Enable Automatic Resynchronization */ - cpc_writeb(falcbase + F_REG(FMR4, ch), - cpc_readb(falcbase + F_REG(FMR4, ch)) | FMR4_AUTO); - - /* Transmit Automatic Remote Alarm */ - cpc_writeb(falcbase + F_REG(FMR2, ch), - cpc_readb(falcbase + F_REG(FMR2, ch)) | FMR2_AXRA); - - /* Channel translation mode 1 : one to one */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_CTM); - - /* No signaling */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_SIGM); - cpc_writeb(falcbase + F_REG(FMR5, ch), - cpc_readb(falcbase + F_REG(FMR5, ch)) & - ~(FMR5_EIBR | FMR5_SRS)); - cpc_writeb(falcbase + F_REG(CCR1, ch), 0); - - cpc_writeb(falcbase + F_REG(LIM1, ch), - cpc_readb(falcbase + F_REG(LIM1, ch)) | LIM1_RIL0 | LIM1_RIL1); - - switch (conf->lbo) { - /* Provides proper Line Build Out */ - case PC300_LBO_0_DB: - cpc_writeb(falcbase + F_REG(LIM2, ch), (LIM2_LOS1 | dja)); - cpc_writeb(falcbase + F_REG(XPM0, ch), 0x5a); - cpc_writeb(falcbase + F_REG(XPM1, ch), 0x8f); - cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20); - break; - case PC300_LBO_7_5_DB: - cpc_writeb(falcbase + F_REG(LIM2, ch), (0x40 | LIM2_LOS1 | dja)); - cpc_writeb(falcbase + F_REG(XPM0, ch), 0x11); - cpc_writeb(falcbase + F_REG(XPM1, ch), 0x02); - cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20); - break; - case PC300_LBO_15_DB: - cpc_writeb(falcbase + F_REG(LIM2, ch), (0x80 | LIM2_LOS1 | dja)); - cpc_writeb(falcbase + F_REG(XPM0, ch), 0x8e); - cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01); - cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20); - break; - case PC300_LBO_22_5_DB: - cpc_writeb(falcbase + F_REG(LIM2, ch), (0xc0 | LIM2_LOS1 | dja)); - cpc_writeb(falcbase + F_REG(XPM0, ch), 0x09); - cpc_writeb(falcbase + F_REG(XPM1, ch), 0x01); - cpc_writeb(falcbase + F_REG(XPM2, ch), 0x20); - break; - } - - /* Transmit Clock-Slot Offset */ - cpc_writeb(falcbase + F_REG(XC0, ch), - cpc_readb(falcbase + F_REG(XC0, ch)) | 0x01); - /* Transmit Time-slot Offset */ - cpc_writeb(falcbase + F_REG(XC1, ch), 0x3e); - /* Receive Clock-Slot offset */ - cpc_writeb(falcbase + F_REG(RC0, ch), 0x05); - /* Receive Time-slot offset */ - cpc_writeb(falcbase + F_REG(RC1, ch), 0x00); - - /* LOS Detection after 176 consecutive 0s */ - cpc_writeb(falcbase + F_REG(PCDR, ch), 0x0a); - /* LOS Recovery after 22 ones in the time window of PCD */ - cpc_writeb(falcbase + F_REG(PCRR, ch), 0x15); - - cpc_writeb(falcbase + F_REG(IDLE, ch), 0x7f); - - if (conf->fr_mode == PC300_FR_ESF_JAPAN) { - cpc_writeb(falcbase + F_REG(RC1, ch), - cpc_readb(falcbase + F_REG(RC1, ch)) | 0x80); - } - - falc_close_all_timeslots(card, ch); -} - -static void falc_init_e1(pc300_t * card, int ch) -{ - pc300ch_t *chan = (pc300ch_t *) & card->chan[ch]; - pc300chconf_t *conf = (pc300chconf_t *) & chan->conf; - falc_t *pfalc = (falc_t *) & chan->falc; - void __iomem *falcbase = card->hw.falcbase; - u8 dja = (ch ? (LIM2_DJA2 | LIM2_DJA1) : 0); - - /* Switch to E1 mode (PCM 30) */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) & ~FMR1_PMOD); - - /* Clock mode */ - if (conf->phys_settings.clock_type == CLOCK_INT) { /* Master mode */ - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) | LIM0_MAS); - } else { /* Slave mode */ - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) & ~LIM0_MAS); - } - cpc_writeb(falcbase + F_REG(LOOP, ch), - cpc_readb(falcbase + F_REG(LOOP, ch)) & ~LOOP_SFM); - - cpc_writeb(falcbase + F_REG(IPC, ch), IPC_SCI); - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) & - ~(FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1)); - - switch (conf->lcode) { - case PC300_LC_AMI: - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | - FMR0_XC1 | FMR0_RC1); - break; - - case PC300_LC_HDB3: - cpc_writeb(falcbase + F_REG(FMR0, ch), - cpc_readb(falcbase + F_REG(FMR0, ch)) | - FMR0_XC0 | FMR0_XC1 | FMR0_RC0 | FMR0_RC1); - break; - - case PC300_LC_NRZ: - break; - } - - cpc_writeb(falcbase + F_REG(LIM0, ch), - cpc_readb(falcbase + F_REG(LIM0, ch)) & ~(LIM0_SCL1 | LIM0_SCL0)); - /* Set interface mode to 2 MBPS */ - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_IMOD); - - cpc_writeb(falcbase + F_REG(XPM0, ch), 0x18); - cpc_writeb(falcbase + F_REG(XPM1, ch), 0x03); - cpc_writeb(falcbase + F_REG(XPM2, ch), 0x00); - - switch (conf->fr_mode) { - case PC300_FR_MF_CRC4: - pfalc->multiframe_mode = 1; - cpc_writeb(falcbase + F_REG(FMR1, ch), - cpc_readb(falcbase + F_REG(FMR1, ch)) | FMR1_XFS); - cpc_writeb(falcbase + F_REG(FMR2, ch), - cpc_readb(falcbase + F_REG(FMR2, ch)) |