lanai.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,038 行 · 第 1/5 页

C
2,038
字号
	Status_Reg		= 0x28,	/* Status */#define   STATUS_PROMDATA	 (0x00000001)	/* PROM_DATA pin */#define   STATUS_WAITING	 (0x00000002)	/* Interrupt being delayed */#define	  STATUS_SOOL		 (0x00000004)	/* SOOL alarm */#define   STATUS_LOCD		 (0x00000008)	/* LOCD alarm */#define	  STATUS_LED		 (0x00000010)	/* LED (HAPPI) output */#define   STATUS_GPIN		 (0x00000020)	/* GPIN pin */#define   STATUS_BUTTBUSY	 (0x00000040)	/* Butt register is pending */	Config1_Reg		= 0x2C,	/* Config word 1; bits: */#define   CONFIG1_PROMDATA	 (0x00000001)	/* PROM_DATA pin */#define   CONFIG1_PROMCLK	 (0x00000002)	/* PROM_CLK pin */#define   CONFIG1_SET_READMODE(x) ((x)*0x004)	/* PCI BM reads; values: */#define     READMODE_PLAIN	    (0)		/*   Plain memory read */#define     READMODE_LINE	    (2)		/*   Memory read line */#define     READMODE_MULTIPLE	    (3)		/*   Memory read multiple */#define   CONFIG1_DMA_ENABLE	 (0x00000010)	/* Turn on DMA */#define   CONFIG1_POWERDOWN	 (0x00000020)	/* Turn off clocks */#define   CONFIG1_SET_LOOPMODE(x) ((x)*0x080)	/* Clock&loop mode; values: */#define     LOOPMODE_NORMAL	    (0)		/*   Normal - no loop */#define     LOOPMODE_TIME	    (1)#define     LOOPMODE_DIAG	    (2)#define     LOOPMODE_LINE	    (3)#define   CONFIG1_MASK_LOOPMODE  (0x00000180)#define   CONFIG1_SET_LEDMODE(x) ((x)*0x0200)	/* Mode of LED; values: */#define     LEDMODE_NOT_SOOL	    (0)		/*   !SOOL */#define	    LEDMODE_OFF		    (1)		/*   0     */#define	    LEDMODE_ON		    (2)		/*   1     */#define	    LEDMODE_NOT_LOCD	    (3)		/*   !LOCD */#define	    LEDMORE_GPIN	    (4)		/*   GPIN  */#define     LEDMODE_NOT_GPIN	    (7)		/*   !GPIN */#define   CONFIG1_MASK_LEDMODE	 (0x00000E00)#define   CONFIG1_GPOUT1	 (0x00001000)	/* Toggle for reset */#define   CONFIG1_GPOUT2	 (0x00002000)	/* Loopback PHY */#define   CONFIG1_GPOUT3	 (0x00004000)	/* Loopback lanai */	Config2_Reg		= 0x30,	/* Config word 2; bits: */#define   CONFIG2_HOWMANY	 (0x00000001)	/* >512 VCIs? */#define   CONFIG2_PTI7_MODE	 (0x00000002)	/* Make PTI=7 RM, not OAM */#define   CONFIG2_VPI_CHK_DIS	 (0x00000004)	/* Ignore RX VPI value */#define   CONFIG2_HEC_DROP	 (0x00000008)	/* Drop cells w/ HEC errors */#define   CONFIG2_VCI0_NORMAL	 (0x00000010)	/* Treat VCI=0 normally */#define   CONFIG2_CBR_ENABLE	 (0x00000020)	/* Deal with CBR traffic */#define   CONFIG2_TRASH_ALL	 (0x00000040)	/* Trashing incoming cells */#define   CONFIG2_TX_DISABLE	 (0x00000080)	/* Trashing outgoing cells */#define   CONFIG2_SET_TRASH	 (0x00000100)	/* Turn trashing on */	Statistics_Reg		= 0x34,	/* Statistics; bits: */#define   STATS_GET_FIFO_OVFL(x)    (((x)>> 0)&0xFF)	/* FIFO overflowed */#define   STATS_GET_HEC_ERR(x)      (((x)>> 8)&0xFF)	/* HEC was bad */#define   STATS_GET_BAD_VCI(x)      (((x)>>16)&0xFF)	/* VCI not open */#define   STATS_GET_BUF_OVFL(x)     (((x)>>24)&0xFF)	/* VCC buffer full */	ServiceStuff_Reg	= 0x38,	/* Service stuff; bits: */#define   SSTUFF_SET_SIZE(x) ((x)*0x20000000)	/* size of service buffer */#define   SSTUFF_SET_ADDR(x)	    ((x)>>8)	/* set address of buffer */	ServWrite_Reg		= 0x3C,	/* ServWrite Pointer */	ServRead_Reg		= 0x40,	/* ServRead Pointer */	TxDepth_Reg		= 0x44,	/* FIFO Transmit Depth */	Butt_Reg		= 0x48,	/* Butt register */	CBR_ICG_Reg		= 0x50,	CBR_PTR_Reg		= 0x54,	PingCount_Reg		= 0x58,	/* Ping count */	DMA_Addr_Reg		= 0x5C	/* DMA address */};static inline bus_addr_t reg_addr(const struct lanai_dev *lanai,	enum lanai_register reg){	return lanai->base + reg;}static inline u32 reg_read(const struct lanai_dev *lanai,	enum lanai_register reg){	u32 t;	t = readl(reg_addr(lanai, reg));	RWDEBUG("R [0x%08X] 0x%02X = 0x%08X\n", (unsigned int) lanai->base,	    (int) reg, t);	return t;}static inline void reg_write(const struct lanai_dev *lanai, u32 val,	enum lanai_register reg){	RWDEBUG("W [0x%08X] 0x%02X < 0x%08X\n", (unsigned int) lanai->base,	    (int) reg, val);	writel(val, reg_addr(lanai, reg));}static inline void conf1_write(const struct lanai_dev *lanai){	reg_write(lanai, lanai->conf1, Config1_Reg);}static inline void conf2_write(const struct lanai_dev *lanai){	reg_write(lanai, lanai->conf2, Config2_Reg);}/* Same as conf2_write(), but defers I/O if we're powered down */static inline void conf2_write_if_powerup(const struct lanai_dev *lanai){#ifdef USE_POWERDOWN	if (unlikely((lanai->conf1 & CONFIG1_POWERDOWN) != 0))		return;#endif /* USE_POWERDOWN */	conf2_write(lanai);}static inline void reset_board(const struct lanai_dev *lanai){	DPRINTK("about to reset board\n");	reg_write(lanai, 0, Reset_Reg);	/*	 * If we don't delay a little while here then we can end up	 * leaving the card in a VERY weird state and lock up the	 * PCI bus.  This isn't documented anywhere but I've convinced	 * myself after a lot of painful experimentation	 */	udelay(5);}/* -------------------- CARD SRAM UTILITIES: *//* The SRAM is mapped into normal PCI memory space - the only catch is * that it is only 16-bits wide but must be accessed as 32-bit.  The * 16 high bits will be zero.  We don't hide this, since they get * programmed mostly like discrete registers anyway */#define SRAM_START (0x20000)#define SRAM_BYTES (0x20000)	/* Again, half don't really exist */static inline bus_addr_t sram_addr(const struct lanai_dev *lanai, int offset){	return lanai->base + SRAM_START + offset;}static inline u32 sram_read(const struct lanai_dev *lanai, int offset){	return readl(sram_addr(lanai, offset));}static inline void sram_write(const struct lanai_dev *lanai,	u32 val, int offset){	writel(val, sram_addr(lanai, offset));}static int __init sram_test_word(	const struct lanai_dev *lanai, int offset, u32 pattern){	u32 readback;	sram_write(lanai, pattern, offset);	readback = sram_read(lanai, offset);	if (likely(readback == pattern))		return 0;	printk(KERN_ERR DEV_LABEL	    "(itf %d): SRAM word at %d bad: wrote 0x%X, read 0x%X\n",	    lanai->number, offset,	    (unsigned int) pattern, (unsigned int) readback);	return -EIO;}static int __init sram_test_pass(const struct lanai_dev *lanai, u32 pattern){	int offset, result = 0;	for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4)		result = sram_test_word(lanai, offset, pattern);	return result;}static int __init sram_test_and_clear(const struct lanai_dev *lanai){#ifdef FULL_MEMORY_TEST	int result;	DPRINTK("testing SRAM\n");	if ((result = sram_test_pass(lanai, 0x5555)) != 0)		return result;	if ((result = sram_test_pass(lanai, 0xAAAA)) != 0)		return result;#endif	DPRINTK("clearing SRAM\n");	return sram_test_pass(lanai, 0x0000);}/* -------------------- CARD-BASED VCC TABLE UTILITIES: *//* vcc table */enum lanai_vcc_offset {	vcc_rxaddr1		= 0x00,	/* Location1, plus bits: */#define   RXADDR1_SET_SIZE(x) ((x)*0x0000100)	/* size of RX buffer */#define   RXADDR1_SET_RMMODE(x) ((x)*0x00800)	/* RM cell action; values: */#define     RMMODE_TRASH	  (0)		/*   discard */#define     RMMODE_PRESERVE	  (1)		/*   input as AAL0 */#define     RMMODE_PIPE		  (2)		/*   pipe to coscheduler */#define     RMMODE_PIPEALL	  (3)		/*   pipe non-RM too */#define   RXADDR1_OAM_PRESERVE	 (0x00002000)	/* Input OAM cells as AAL0 */#define   RXADDR1_SET_MODE(x) ((x)*0x0004000)	/* Reassembly mode */#define     RXMODE_TRASH	  (0)		/*   discard */#define     RXMODE_AAL0		  (1)		/*   non-AAL5 mode */#define     RXMODE_AAL5		  (2)		/*   AAL5, intr. each PDU */#define     RXMODE_AAL5_STREAM	  (3)		/*   AAL5 w/o per-PDU intr */	vcc_rxaddr2		= 0x04,	/* Location2 */	vcc_rxcrc1		= 0x08,	/* RX CRC claculation space */	vcc_rxcrc2		= 0x0C,	vcc_rxwriteptr		= 0x10, /* RX writeptr, plus bits: */#define   RXWRITEPTR_LASTEFCI	 (0x00002000)	/* Last PDU had EFCI bit */#define   RXWRITEPTR_DROPPING	 (0x00004000)	/* Had error, dropping */#define   RXWRITEPTR_TRASHING	 (0x00008000)	/* Trashing */	vcc_rxbufstart		= 0x14,	/* RX bufstart, plus bits: */#define   RXBUFSTART_CLP	 (0x00004000)#define   RXBUFSTART_CI		 (0x00008000)	vcc_rxreadptr		= 0x18,	/* RX readptr */	vcc_txicg		= 0x1C, /* TX ICG */	vcc_txaddr1		= 0x20,	/* Location1, plus bits: */#define   TXADDR1_SET_SIZE(x) ((x)*0x0000100)	/* size of TX buffer */#define   TXADDR1_ABR		 (0x00008000)	/* use ABR (doesn't work) */	vcc_txaddr2		= 0x24,	/* Location2 */	vcc_txcrc1		= 0x28,	/* TX CRC claculation space */	vcc_txcrc2		= 0x2C,	vcc_txreadptr		= 0x30, /* TX Readptr, plus bits: */#define   TXREADPTR_GET_PTR(x) ((x)&0x01FFF)#define   TXREADPTR_MASK_DELTA	(0x0000E000)	/* ? */	vcc_txendptr		= 0x34, /* TX Endptr, plus bits: */#define   TXENDPTR_CLP		(0x00002000)#define   TXENDPTR_MASK_PDUMODE	(0x0000C000)	/* PDU mode; values: */#define     PDUMODE_AAL0	 (0*0x04000)#define     PDUMODE_AAL5	 (2*0x04000)#define     PDUMODE_AAL5STREAM	 (3*0x04000)	vcc_txwriteptr		= 0x38,	/* TX Writeptr */#define   TXWRITEPTR_GET_PTR(x) ((x)&0x1FFF)	vcc_txcbr_next		= 0x3C	/* # of next CBR VCI in ring */#define   TXCBR_NEXT_BOZO	(0x00008000)	/* "bozo bit" */};#define CARDVCC_SIZE	(0x40)static inline bus_addr_t cardvcc_addr(const struct lanai_dev *lanai,	vci_t vci){	return sram_addr(lanai, vci * CARDVCC_SIZE);}static inline u32 cardvcc_read(const struct lanai_vcc *lvcc,	enum lanai_vcc_offset offset){	u32 val;	APRINTK(lvcc->vbase != 0, "cardvcc_read: unbound vcc!\n");	val= readl(lvcc->vbase + offset);	RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n",	    lvcc->vci, (int) offset, val);	return val;}static inline void cardvcc_write(const struct lanai_vcc *lvcc,	u32 val, enum lanai_vcc_offset offset){	APRINTK(lvcc->vbase != 0, "cardvcc_write: unbound vcc!\n");	APRINTK((val & ~0xFFFF) == 0,	    "cardvcc_write: bad val 0x%X (vci=%d, addr=0x%02X)\n",	    (unsigned int) val, lvcc->vci, (unsigned int) offset);	RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n",	    lvcc->vci, (unsigned int) offset, (unsigned int) val);	writel(val, lvcc->vbase + offset);}/* -------------------- COMPUTE SIZE OF AN AAL5 PDU: *//* How many bytes will an AAL5 PDU take to transmit - remember that: *   o  we need to add 8 bytes for length, CPI, UU, and CRC *   o  we need to round up to 48 bytes for cells */static inline int aal5_size(int size){	int cells = (size + 8 + 47) / 48;	return cells * 48;}/* How many bytes can we send if we have "space" space, assuming we have * to send full cells */static inline int aal5_spacefor(int space){	int cells = space / 48;	return cells * 48;}/* -------------------- FREE AN ATM SKB: */static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb){	if (atmvcc->pop != NULL)		atmvcc->pop(atmvcc, skb);	else		dev_kfree_skb_any(skb);}/* -------------------- TURN VCCS ON AND OFF: */static void host_vcc_start_rx(const struct lanai_vcc *lvcc){	u32 addr1;	if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) {		dma_addr_t dmaaddr = lvcc->rx.buf.dmaaddr;		cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1);		cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2);		cardvcc_write(lvcc, 0, vcc_rxwriteptr);		cardvcc_write(lvcc, 0, vcc_rxbufstart);		cardvcc_write(lvcc, 0, vcc_rxreadptr);		cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_rxaddr2);		addr1 = ((dmaaddr >> 8) & 0xFF) |		    RXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->rx.buf))|		    RXADDR1_SET_RMMODE(RMMODE_TRASH) |	/* ??? */		 /* RXADDR1_OAM_PRESERVE |	--- no OAM support yet */		    RXADDR1_SET_MODE(RXMODE_AAL5);	} else		addr1 = RXADDR1_SET_RMMODE(RMMODE_PRESERVE) | /* ??? */		    RXADDR1_OAM_PRESERVE |		      /* ??? */		    RXADDR1_SET_MODE(RXMODE_AAL0);	/* This one must be last! */	cardvcc_write(lvcc, addr1, vcc_rxaddr1);}static void host_vcc_start_tx(const struct lanai_vcc *lvcc){	dma_addr_t dmaaddr = lvcc->tx.buf.dmaaddr;	cardvcc_write(lvcc, 0, vcc_txicg);	cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1);	cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2);	cardvcc_write(lvcc, 0, vcc_txreadptr);	cardvcc_write(lvcc, 0, vcc_txendptr);	cardvcc_write(lvcc, 0, vcc_txwriteptr);	cardvcc_write(lvcc,		(lvcc->tx.atmvcc->qos.txtp.traffic_class == ATM_CBR) ?		TXCBR_NEXT_BOZO | lvcc->vci : 0, vcc_txcbr_next);	cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_txaddr2);	cardvcc_write(lvcc,	    ((dmaaddr >> 8) & 0xFF) |	    TXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->tx.buf)),	    vcc_txaddr1);}/* Shutdown receiving on card */static void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc){	if (lvcc->vbase == 0)		/* We were never bound to a VCI */		return;	/* 15.1.1 - set to trashing, wait one cell time (15us) */	cardvcc_write(lvcc,	    RXADDR1_SET_RMMODE(RMMODE_TRASH) |	    RXADDR1_SET_MODE(RXMODE_TRASH), vcc_rxaddr1);	udelay(15);	/* 15.1.2 - clear rest of entries */	cardvcc_write(lvcc, 0, vcc_rxaddr2);	cardvcc_write(lvcc, 0, vcc_rxcrc1);	cardvcc_write(lvcc, 0, vcc_rxcrc2);	cardvcc_write(lvcc, 0, vcc_rxwriteptr);	cardvcc_write(lvcc, 0, vcc_rxbufstart);	cardvcc_write(lvcc, 0, vcc_rxreadptr);}/* Shutdown transmitting on card. * Unfortunately the lanai needs us to wait until all the data * drains out of the buffer before we can dealloc it, so this * can take awhile -- up to 370ms for a full 128KB buffer * assuming everone else is quiet.  In theory the time is * boundless if there's a CBR VCC holding things up. */static void lanai_shutdown_tx_vci(struct lanai_dev *lanai,	struct lanai_vcc *lvcc){	struct sk_buff *skb;	unsigned long flags, timeout;	int read, write, lastread = -1;	APRINTK(!in_interrupt(),	    "lanai_shutdown_tx_vci called w/o process context!\n");	if (lvcc->vbase == 0)		/* We were never bound to a VCI */		return;	/* 15.2.1 - wait for queue to drain */	while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL)		lanai_free_skb(lvcc->tx.atmvcc, skb);	read_lock_irqsave(&vcc_sklist_lock, flags);	__clear_bit(lvcc->vci, lanai->backlog_vccs);	read_unlock_irqrestore(&vcc_sklist_lock, flags);	/*	 * We need to wait for the VCC to drain but don't wait forever.  We	 * give each 1K of buffer size 1/128th of a second to clear out.	 * TODO: maybe disable CBR if we're about to timeout?	 */	timeout = jiffies +	    (((lanai_buf_size(&lvcc->tx.buf) / 1024) * HZ) >> 7);	write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr));	for (;;) {		read = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr));		if (read == write &&	   /* Is TX buffer empty? */		    (lvcc->tx.atmvcc->qos.txtp.traffic_class != ATM_CBR ||		    (cardvcc_read(lvcc, vcc_txcbr_next) &		    TXCBR_NEXT_BOZO) == 0))			break;		if (read != lastread) {	   /* Has there been any progress? */			lastread = read;			timeout += HZ / 10;		}		if (unlikely(time_after(jiffies, timeout))) {			printk(KERN_ERR DEV_LABEL "(itf %d): Timed out on "			    "backlog closing vci %d\n",			    lvcc->tx.atmvcc->dev->number, lvcc->vci);			DPRINTK("read, write = %d, %d\n", read, write);			break;		}		msleep(40);

⌨️ 快捷键说明

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