⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dscc4.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * drivers/net/wan/dscc4/dscc4.c: a DSCC4 HDLC driver for Linux * * This software may be used and distributed according to the terms of the * GNU General Public License. * * The author may be reached as romieu@cogenit.fr. * Specific bug reports/asian food will be welcome. * * Special thanks to the nice people at CS-Telecom for the hardware and the * access to the test/measure tools. * * *                             Theory of Operation * * I. Board Compatibility * * This device driver is designed for the Siemens PEB20534 4 ports serial * controller as found on Etinc PCISYNC cards. The documentation for the * chipset is available at http://www.infineon.com: * - Data Sheet "DSCC4, DMA Supported Serial Communication Controller with * 4 Channels, PEB 20534 Version 2.1, PEF 20534 Version 2.1"; * - Application Hint "Management of DSCC4 on-chip FIFO resources". * - Errata sheet DS5 (courtesy of Michael Skerritt). * Jens David has built an adapter based on the same chipset. Take a look * at http://www.afthd.tu-darmstadt.de/~dg1kjd/pciscc4 for a specific * driver. * Sample code (2 revisions) is available at Infineon. * * II. Board-specific settings * * Pcisync can transmit some clock signal to the outside world on the * *first two* ports provided you put a quartz and a line driver on it and * remove the jumpers. The operation is described on Etinc web site. If you * go DCE on these ports, don't forget to use an adequate cable. * * Sharing of the PCI interrupt line for this board is possible. * * III. Driver operation * * The rx/tx operations are based on a linked list of descriptors. The driver * doesn't use HOLD mode any more. HOLD mode is definitely buggy and the more * I tried to fix it, the more it started to look like (convoluted) software * mutation of LxDA method. Errata sheet DS5 suggests to use LxDA: consider * this a rfc2119 MUST. * * Tx direction * When the tx ring is full, the xmit routine issues a call to netdev_stop. * The device is supposed to be enabled again during an ALLS irq (we could * use HI but as it's easy to lose events, it's fscked). * * Rx direction * The received frames aren't supposed to span over multiple receiving areas. * I may implement it some day but it isn't the highest ranked item. * * IV. Notes * The current error (XDU, RFO) recovery code is untested. * So far, RDO takes his RX channel down and the right sequence to enable it * again is still a mistery. If RDO happens, plan a reboot. More details * in the code (NB: as this happens, TX still works). * Don't mess the cables during operation, especially on DTE ports. I don't * suggest it for DCE either but at least one can get some messages instead * of a complete instant freeze. * Tests are done on Rev. 20 of the silicium. The RDO handling changes with * the documentation/chipset releases. * * TODO: * - test X25. * - use polling at high irq/s, * - performance analysis, * - endianness. * * 2001/12/10	Daniela Squassoni  <daniela@cyclades.com> * - Contribution to support the new generic HDLC layer. * * 2002/01	Ueimor * - old style interface removal * - dscc4_release_ring fix (related to DMA mapping) * - hard_start_xmit fix (hint: TxSizeMax) * - misc crapectomy. */#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/list.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/mm.h>#include <asm/system.h>#include <asm/cache.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/irq.h>#include <linux/init.h>#include <linux/string.h>#include <linux/if_arp.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/delay.h>#include <net/syncppp.h>#include <linux/hdlc.h>/* Version */static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n";static int debug;static int quartz;#ifdef CONFIG_DSCC4_PCI_RSTstatic DECLARE_MUTEX(dscc4_sem);static u32 dscc4_pci_config_store[16];#endif#define	DRV_NAME	"dscc4"#undef DSCC4_POLLING/* Module parameters */MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");MODULE_DESCRIPTION("Siemens PEB20534 PCI Controler");MODULE_LICENSE("GPL");module_param(debug, int, 0);MODULE_PARM_DESC(debug,"Enable/disable extra messages");module_param(quartz, int, 0);MODULE_PARM_DESC(quartz,"If present, on-board quartz frequency (Hz)");/* Structures */struct thingie {	int define;	u32 bits;};struct TxFD {	u32 state;	u32 next;	u32 data;	u32 complete;	u32 jiffies; /* Allows sizeof(TxFD) == sizeof(RxFD) + extra hack */};struct RxFD {	u32 state1;	u32 next;	u32 data;	u32 state2;	u32 end;};#define DUMMY_SKB_SIZE		64#define TX_LOW			8#define TX_RING_SIZE		32#define RX_RING_SIZE		32#define TX_TOTAL_SIZE		TX_RING_SIZE*sizeof(struct TxFD)#define RX_TOTAL_SIZE		RX_RING_SIZE*sizeof(struct RxFD)#define IRQ_RING_SIZE		64		/* Keep it a multiple of 32 */#define TX_TIMEOUT		(HZ/10)#define DSCC4_HZ_MAX		33000000#define BRR_DIVIDER_MAX		64*0x00004000	/* Cf errata DS5 p.10 */#define dev_per_card		4#define SCC_REGISTERS_MAX	23		/* Cf errata DS5 p.4 */#define SOURCE_ID(flags)	(((flags) >> 28) & 0x03)#define TO_SIZE(state)		(((state) >> 16) & 0x1fff)/* * Given the operating range of Linux HDLC, the 2 defines below could be * made simpler. However they are a fine reminder for the limitations of * the driver: it's better to stay < TxSizeMax and < RxSizeMax. */#define TO_STATE_TX(len)	cpu_to_le32(((len) & TxSizeMax) << 16)#define TO_STATE_RX(len)	cpu_to_le32((RX_MAX(len) % RxSizeMax) << 16)#define RX_MAX(len)		((((len) >> 5) + 1) << 5)	/* Cf RLCR */#define SCC_REG_START(dpriv)	(SCC_START+(dpriv->dev_id)*SCC_OFFSET)struct dscc4_pci_priv {        u32 *iqcfg;        int cfg_cur;        spinlock_t lock;        struct pci_dev *pdev;        struct dscc4_dev_priv *root;        dma_addr_t iqcfg_dma;	u32 xtal_hz;};struct dscc4_dev_priv {        struct sk_buff *rx_skbuff[RX_RING_SIZE];        struct sk_buff *tx_skbuff[TX_RING_SIZE];        struct RxFD *rx_fd;        struct TxFD *tx_fd;        u32 *iqrx;        u32 *iqtx;	/* FIXME: check all the volatile are required */        volatile u32 tx_current;        u32 rx_current;        u32 iqtx_current;        u32 iqrx_current;        volatile u32 tx_dirty;        volatile u32 ltda;        u32 rx_dirty;        u32 lrda;        dma_addr_t tx_fd_dma;        dma_addr_t rx_fd_dma;        dma_addr_t iqtx_dma;        dma_addr_t iqrx_dma;	u32 scc_regs[SCC_REGISTERS_MAX]; /* Cf errata DS5 p.4 */	struct timer_list timer;        struct dscc4_pci_priv *pci_priv;        spinlock_t lock;        int dev_id;	volatile u32 flags;	u32 timer_help;	unsigned short encoding;	unsigned short parity;	struct net_device *dev;	sync_serial_settings settings;	void __iomem *base_addr;	u32 __pad __attribute__ ((aligned (4)));};/* GLOBAL registers definitions */#define GCMDR   0x00#define GSTAR   0x04#define GMODE   0x08#define IQLENR0 0x0C#define IQLENR1 0x10#define IQRX0   0x14#define IQTX0   0x24#define IQCFG   0x3c#define FIFOCR1 0x44#define FIFOCR2 0x48#define FIFOCR3 0x4c#define FIFOCR4 0x34#define CH0CFG  0x50#define CH0BRDA 0x54#define CH0BTDA 0x58#define CH0FRDA 0x98#define CH0FTDA 0xb0#define CH0LRDA 0xc8#define CH0LTDA 0xe0/* SCC registers definitions */#define SCC_START	0x0100#define SCC_OFFSET      0x80#define CMDR    0x00#define STAR    0x04#define CCR0    0x08#define CCR1    0x0c#define CCR2    0x10#define BRR     0x2C#define RLCR    0x40#define IMR     0x54#define ISR     0x58#define GPDIR	0x0400#define GPDATA	0x0404#define GPIM	0x0408/* Bit masks */#define EncodingMask	0x00700000#define CrcMask		0x00000003#define IntRxScc0	0x10000000#define IntTxScc0	0x01000000#define TxPollCmd	0x00000400#define RxActivate	0x08000000#define MTFi		0x04000000#define Rdr		0x00400000#define Rdt		0x00200000#define Idr		0x00100000#define Idt		0x00080000#define TxSccRes	0x01000000#define RxSccRes	0x00010000#define TxSizeMax	0x1fff		/* Datasheet DS1 - 11.1.1.1 */#define RxSizeMax	0x1ffc		/* Datasheet DS1 - 11.1.2.1 */#define Ccr0ClockMask	0x0000003f#define Ccr1LoopMask	0x00000200#define IsrMask		0x000fffff#define BrrExpMask	0x00000f00#define BrrMultMask	0x0000003f#define EncodingMask	0x00700000#define Hold		0x40000000#define SccBusy		0x10000000#define PowerUp		0x80000000#define Vis		0x00001000#define FrameOk		(FrameVfr | FrameCrc)#define FrameVfr	0x80#define FrameRdo	0x40#define FrameCrc	0x20#define FrameRab	0x10#define FrameAborted	0x00000200#define FrameEnd	0x80000000#define DataComplete	0x40000000#define LengthCheck	0x00008000#define SccEvt		0x02000000#define NoAck		0x00000200#define Action		0x00000001#define HiDesc		0x20000000/* SCC events */#define RxEvt		0xf0000000#define TxEvt		0x0f000000#define Alls		0x00040000#define Xdu		0x00010000#define Cts		0x00004000#define Xmr		0x00002000#define Xpr		0x00001000#define Rdo		0x00000080#define Rfs		0x00000040#define Cd		0x00000004#define Rfo		0x00000002#define Flex		0x00000001/* DMA core events */#define Cfg		0x00200000#define Hi		0x00040000#define Fi		0x00020000#define Err		0x00010000#define Arf		0x00000002#define ArAck		0x00000001/* State flags */#define Ready		0x00000000#define NeedIDR		0x00000001#define NeedIDT		0x00000002#define RdoSet		0x00000004#define FakeReset	0x00000008/* Don't mask RDO. Ever. */#ifdef DSCC4_POLLING#define EventsMask	0xfffeef7f#else#define EventsMask	0xfffa8f7a#endif/* Functions prototypes */static void dscc4_rx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);static void dscc4_tx_irq(struct dscc4_pci_priv *, struct dscc4_dev_priv *);static int dscc4_found1(struct pci_dev *, void __iomem *ioaddr);static int dscc4_init_one(struct pci_dev *, const struct pci_device_id *ent);static int dscc4_open(struct net_device *);static int dscc4_start_xmit(struct sk_buff *, struct net_device *);static int dscc4_close(struct net_device *);static int dscc4_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static int dscc4_init_ring(struct net_device *);static void dscc4_release_ring(struct dscc4_dev_priv *);static void dscc4_timer(unsigned long);static void dscc4_tx_timeout(struct net_device *);static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short);static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);#ifdef DSCC4_POLLINGstatic int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);#endifstatic inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev){	return dev_to_hdlc(dev)->priv;}static inline struct net_device *dscc4_to_dev(struct dscc4_dev_priv *p){	return p->dev;}static void scc_patchl(u32 mask, u32 value, struct dscc4_dev_priv *dpriv,			struct net_device *dev, int offset){	u32 state;	/* Cf scc_writel for concern regarding thread-safety */	state = dpriv->scc_regs[offset >> 2];	state &= ~mask;	state |= value;	dpriv->scc_regs[offset >> 2] = state;	writel(state, dpriv->base_addr + SCC_REG_START(dpriv) + offset);}static void scc_writel(u32 bits, struct dscc4_dev_priv *dpriv,		       struct net_device *dev, int offset){	/*	 * Thread-UNsafe.	 * As of 2002/02/16, there are no thread racing for access.	 */	dpriv->scc_regs[offset >> 2] = bits;	writel(bits, dpriv->base_addr + SCC_REG_START(dpriv) + offset);}static inline u32 scc_readl(struct dscc4_dev_priv *dpriv, int offset){	return dpriv->scc_regs[offset >> 2];}static u32 scc_readl_star(struct dscc4_dev_priv *dpriv, struct net_device *dev){	/* Cf errata DS5 p.4 */	readl(dpriv->base_addr + SCC_REG_START(dpriv) + STAR);	return readl(dpriv->base_addr + SCC_REG_START(dpriv) + STAR);}static inline void dscc4_do_tx(struct dscc4_dev_priv *dpriv,			       struct net_device *dev){	dpriv->ltda = dpriv->tx_fd_dma +                      ((dpriv->tx_current-1)%TX_RING_SIZE)*sizeof(struct TxFD);	writel(dpriv->ltda, dpriv->base_addr + CH0LTDA + dpriv->dev_id*4);	/* Flush posted writes *NOW* */	readl(dpriv->base_addr + CH0LTDA + dpriv->dev_id*4);}static inline void dscc4_rx_update(struct dscc4_dev_priv *dpriv,				   struct net_device *dev){	dpriv->lrda = dpriv->rx_fd_dma +		      ((dpriv->rx_dirty - 1)%RX_RING_SIZE)*sizeof(struct RxFD);	writel(dpriv->lrda, dpriv->base_addr + CH0LRDA + dpriv->dev_id*4);}static inline unsigned int dscc4_tx_done(struct dscc4_dev_priv *dpriv){	return dpriv->tx_current == dpriv->tx_dirty;}static inline unsigned int dscc4_tx_quiescent(struct dscc4_dev_priv *dpriv,					      struct net_device *dev){	return readl(dpriv->base_addr + CH0FTDA + dpriv->dev_id*4) == dpriv->ltda;}static int state_check(u32 state, struct dscc4_dev_priv *dpriv,		       struct net_device *dev, const char *msg){	int ret = 0;	if (debug > 1) {	if (SOURCE_ID(state) != dpriv->dev_id) {		printk(KERN_DEBUG "%s (%s): Source Id=%d, state=%08x\n",		       dev->name, msg, SOURCE_ID(state), state );			ret = -1;	}	if (state & 0x0df80c00) {		printk(KERN_DEBUG "%s (%s): state=%08x (UFO alert)\n",		       dev->name, msg, state);			ret = -1;	}	}	return ret;}static void dscc4_tx_print(struct net_device *dev,			   struct dscc4_dev_priv *dpriv,			   char *msg){	printk(KERN_DEBUG "%s: tx_current=%02d tx_dirty=%02d (%s)\n",	       dev->name, dpriv->tx_current, dpriv->tx_dirty, msg);}static void dscc4_release_ring(struct dscc4_dev_priv *dpriv){	struct pci_dev *pdev = dpriv->pci_priv->pdev;	struct TxFD *tx_fd = dpriv->tx_fd;	struct RxFD *rx_fd = dpriv->rx_fd;	struct sk_buff **skbuff;	int i;	pci_free_consistent(pdev, TX_TOTAL_SIZE, tx_fd, dpriv->tx_fd_dma);	pci_free_consistent(pdev, RX_TOTAL_SIZE, rx_fd, dpriv->rx_fd_dma);	skbuff = dpriv->tx_skbuff;	for (i = 0; i < TX_RING_SIZE; i++) {		if (*skbuff) {			pci_unmap_single(pdev, tx_fd->data, (*skbuff)->len,				PCI_DMA_TODEVICE);			dev_kfree_skb(*skbuff);		}		skbuff++;		tx_fd++;	}	skbuff = dpriv->rx_skbuff;	for (i = 0; i < RX_RING_SIZE; i++) {		if (*skbuff) {			pci_unmap_single(pdev, rx_fd->data,				RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE);			dev_kfree_skb(*skbuff);		}		skbuff++;		rx_fd++;	}}static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv,				 struct net_device *dev){	unsigned int dirty = dpriv->rx_dirty%RX_RING_SIZE;	struct RxFD *rx_fd = dpriv->rx_fd + dirty;	const int len = RX_MAX(HDLC_MAX_MRU);	struct sk_buff *skb;	int ret = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -