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 + -
显示快捷键?