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

📄 lanai.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Returns buf->order<0 if no memory * Note that the size will be rounded up to an "order" of pages, and * if we can't allocate that we'll settle for something smaller * until minbytes * * NOTE: buffer must be 32-bit DMA capable - when linux can *	 make distinction, this will need tweaking for this *	 to work on BIG memory machines. */static void lanai_buf_allocate(struct lanai_buffer *buf,	int bytes, int minbytes){	unsigned long address;	int order = bytes_to_order(bytes);	do {		address = __get_free_pages(GFP_KERNEL, order);		if (address != 0) {	/* Success */			bytes = PAGE_SIZE << order;			buf->start = buf->ptr = (u32 *) address;			buf->end = (u32 *) (address + bytes);			memset((void *) address, 0, bytes);			break;		}		if ((PAGE_SIZE << --order) < minbytes)			order = -1;	/* Too small - give up */	} while (order >= 0);	buf->order = order;}static inline void lanai_buf_deallocate(struct lanai_buffer *buf){	if (buf->order >= 0) {		APRINTK(buf->start != 0, "lanai_buf_deallocate: start==0!\n");		free_pages((unsigned long) buf->start, buf->order);		buf->start = buf->end = buf->ptr = 0;	}}/* size of buffer in bytes */static inline int lanai_buf_size(const struct lanai_buffer *buf){	return ((unsigned long) buf->end) - ((unsigned long) buf->start);}/* size of buffer as "card order" (0=1k .. 7=128k) */static inline int lanai_buf_size_cardorder(const struct lanai_buffer *buf){	return buf->order + PAGE_SHIFT - 10;}/* DMA-able address for this buffer */static unsigned long lanai_buf_dmaaddr(const struct lanai_buffer *buf){	unsigned long r = virt_to_bus(buf->start);	APRINTK((r & ~0xFFFFFF00) == 0, "bad dmaaddr: 0x%lx\n", (long) r);	return r;}/* -------------------- HANDLE BACKLOG_VCCS BITFIELD: */static inline void vcc_mark_backlogged(struct lanai_dev *lanai,	const struct lanai_vcc *lvcc){	APRINTK(lvcc->vbase != 0, "vcc_mark_backlogged: zero vbase!\n");	vci_bitfield_set(&lanai->backlog_vccs, lvcc->vci);}static inline void vcc_unmark_backlogged(struct lanai_dev *lanai,	const struct lanai_vcc *lvcc){	APRINTK(lvcc->vbase != 0, "vcc_unmark_backlogged: zero vbase!\n");	vci_bitfield_clear(&lanai->backlog_vccs, lvcc->vci);}static inline void vcc_backlog_init(struct lanai_dev *lanai){	vci_bitfield_init(&lanai->backlog_vccs);}static inline int vcc_is_backlogged(/*const*/ struct lanai_vcc *lvcc){	return lvcc->tx.inprogress != NULL ||	    !skb_queue_empty(&lvcc->tx.backlog);}/* -------------------- PORT I/O UTILITIES: *//* Registers (and their bit-fields) */enum lanai_register {	Reset_Reg		= 0x00,	/* Reset; read for chip type; bits: */#define   RESET_GET_BOARD_REV(x)    (((x)>> 0)&0x03)	/* Board revision */#define   RESET_GET_BOARD_ID(x)	    (((x)>> 2)&0x03)	/* Board ID */#define     BOARD_ID_LANAI256		(0)	/* 25.6M adaptor card */	Endian_Reg		= 0x04,	/* Endian setting */	IntStatus_Reg		= 0x08,	/* Interrupt status */	IntStatusMasked_Reg	= 0x0C,	/* Interrupt status (masked) */	IntAck_Reg		= 0x10,	/* Interrupt acknowledge */	IntAckMasked_Reg	= 0x14,	/* Interrupt acknowledge (masked) */	IntStatusSet_Reg	= 0x18,	/* Get status + enable/disable */	IntStatusSetMasked_Reg	= 0x1C,	/* Get status + en/di (masked) */	IntControlEna_Reg	= 0x20,	/* Interrupt control enable */	IntControlDis_Reg	= 0x24,	/* Interrupt control disable */	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 + (bus_addr_t) 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));	mdelay(1);}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);}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);}/* -------------------- VCC LIST LOCK: *//* * The linux-atm code disables local IRQs while managing the list of * VCCs on a card.  This is good, but it doesn't save us against * SMP.  Unfortunately, fixing this will require changes in the * API which will have to wait a little bit.  It's a hard race to * trigger accidentally, so it isn't TOO horrible so far. * * One possible solution would be to have an rwlock which is * always grabbed _irq-style on writing.  This would automatically * be grabbed (for writing) by the higher layers on things that * would result in a change in the vcc list (_open, _close, * probably _change_qos) - thus it would also protect the * higher-level list of vccs on each device (atm_dev->vccs). * The driver would be responsible for grabbing it as a read_lock * anytime it wants to consult its table of vccs - for instance * when handling an incoming PDU.  This also explains why we would * probably want the write_lock while in _change_qos - to prevent * handling of PDUs while possibly in an inconsistant state. * Also, _send would grab the lock for reading. * * One problem with this is that _open and _close could no longer * do anything that might provoke a schedule.  First, it would * force us to use GFP_ATOMIC memory (which is bad), but also * some devices pretty much require scheduling due to long * delays (see lanai_close for an example).  So in this case * we need a way to schedule without losing the spinlock. * The cleanest way to do this is probably have a way to mark a * VCC as "in progress" so that the interrupt handler can * still disregard any traffic for it while _open or _close * are sleeping on it.  Then it will need to be _open and * _close's job to relinquish the write_lock.  Thus, the * lock could be dropped around the times that scheduling * might occur.  Perhaps the _READY flag can be used for * this purpose. * * One short note about this "upper layer grabs, driver * relinquishes" write lock - since this needs to be * an _irq lock we're going to have problem saving * and restoring flags (_irqsave/_irqrestore).  This * shouldn't be a problem, however - we must just * require that those syscalls are never called with * interrupts disabled so we can use the non-flags-saving * versions. * * Anyway, all of the above is vaporware currently - fixing * this right will require changes in the API and all of * the drivers - this will wait until 2.5.x most likely. * The following NOP macros are just here to mark where * the locks will be needed in the future. */#define vcclist_read_lock()	do {} while (0)#define vcclist_read_unlock()	do {} while (0)#define vcclist_write_lock()	do {} while (0)#define vcclist_write_unlock()	do {} while (0)/* -------------------- 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 (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, pattern, 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 + (bus_addr_t) 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,

⌨️ 快捷键说明

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