📄 lanai.c
字号:
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", val, lvcc->vci, (int) offset); RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", lvcc->vci, (int) offset, val); writel(val, lvcc->vbase + (bus_addr_t) 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) { unsigned long dmaaddr = lanai_buf_dmaaddr(&lvcc->rx.buf); 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){ unsigned long dmaaddr = lanai_buf_dmaaddr(&lvcc->tx.buf); 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 */ spin_lock_irqsave(&lanai->txlock, flags); if (lvcc->tx.inprogress != NULL) { lanai_free_skb(lvcc->tx.atmvcc, lvcc->tx.inprogress); lvcc->tx.inprogress = NULL; } while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL) lanai_free_skb(lvcc->tx.atmvcc, skb); vcc_unmark_backlogged(lanai, lvcc); spin_unlock_irqrestore(&lanai->txlock, flags); timeout = jiffies + ((lanai_buf_size(&lvcc->tx.buf) * HZ) >> 17); write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr)); goto start; while (time_before_eq(jiffies, timeout)) { schedule_timeout(HZ / 25); start: 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)) goto done; if (read != lastread) { /* Has there been any progress? */ lastread = read; timeout += HZ / 10; } } 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); done: /* 15.2.2 - clear out all tx registers */ cardvcc_write(lvcc, 0, vcc_txreadptr); cardvcc_write(lvcc, 0, vcc_txwriteptr); cardvcc_write(lvcc, 0, vcc_txendptr); cardvcc_write(lvcc, 0, vcc_txcrc1); cardvcc_write(lvcc, 0, vcc_txcrc2); cardvcc_write(lvcc, 0, vcc_txaddr2); cardvcc_write(lvcc, 0, vcc_txaddr1);}/* -------------------- MANAGING AAL0 RX BUFFER: */static inline int aal0_buffer_allocate(struct lanai_dev *lanai){ DPRINTK("aal0_buffer_allocate: allocating AAL0 RX buffer\n"); lanai_buf_allocate(&lanai->aal0buf, AAL0_RX_BUFFER_SIZE, 80); return (lanai->aal0buf.order < 0) ? -ENOMEM : 0;}static inline void aal0_buffer_free(struct lanai_dev *lanai){ DPRINTK("aal0_buffer_allocate: freeing AAL0 RX buffer\n"); lanai_buf_deallocate(&lanai->aal0buf);}/* -------------------- EEPROM UTILITIES: *//* Offsets of data in the EEPROM */#define EEPROM_COPYRIGHT (0)#define EEPROM_COPYRIGHT_LEN (44)#define EEPROM_CHECKSUM (62)#define EEPROM_CHECKSUM_REV (63)#define EEPROM_MAC (64)#define EEPROM_MAC_REV (70)#define EEPROM_SERIAL (112)#define EEPROM_SERIAL_REV (116)#define EEPROM_MAGIC (120)#define EEPROM_MAGIC_REV (124)#define EEPROM_MAGIC_VALUE (0x5AB478D2)#ifndef READ_EEPROM/* Stub functions to use if EEPROM reading is disabled */static int __init eeprom_read(struct lanai_dev *lanai){ printk(KERN_INFO DEV_LABEL "(itf %d): *NOT* reading EEPROM\n", lanai->number); memset(&lanai->eeprom[EEPROM_MAC], 0, 6); return 0;}static int __init eeprom_validate(struct lanai_dev *lanai){ lanai->serialno = 0; lanai->magicno = EEPROM_MAGIC_VALUE; return 0;}#else /* READ_EEPROM */static int __init eeprom_read(struct lanai_dev *lanai){ int i, address; u8 data; u32 tmp;#define set_config1(x) do { lanai->conf1 = x; conf1_write(lanai); \ } while (0)#define clock_h() set_config1(lanai->conf1 | CONFIG1_PROMCLK)#define clock_l() set_config1(lanai->conf1 &~ CONFIG1_PROMCLK)#define data_h() set_config1(lanai->conf1 | CONFIG1_PROMDATA)#define data_l() set_config1(lanai->conf1 &~ CONFIG1_PROMDATA)#define pre_read() do { data_h(); clock_h(); udelay(5); } while (0)#define read_pin() (reg_read(lanai, Status_Reg) & STATUS_PROMDATA)#define send_stop() do { data_l(); udelay(5); clock_h(); udelay(5); \ data_h(); udelay(5); } while (0) /* start with both clock and data high */ data_h(); clock_h(); udelay(5); for (address = 0; address < LANAI_EEPROM_SIZE; address++) { data = (address << 1) | 1; /* Command=read + address */ /* send start bit */ data_l(); udelay(5); clock_l(); udelay(5); for (i = 128; i != 0; i >>= 1) { /* write command out */ tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) | (data & i) ? CONFIG1_PROMDATA : 0; if (lanai->conf1 != tmp) { set_config1(tmp); udelay(5); /* Let new data settle */ } clock_h(); udelay(5); clock_l(); udelay(5); } /* look for ack */ data_h(); clock_h(); udelay(5); if (read_pin() != 0) goto error; /* No ack seen */ clock_l(); udelay(5); /* read back result */ for (data = 0, i = 7; i >= 0; i--) { data_h(); clock_h(); udelay(5); data = (data << 1) | !!read_pin(); clock_l(); udelay(5); } /* look again for ack */ data_h(); clock_h(); udelay(5); if (read_pin() == 0) goto error; /* Spurious ack */ clock_l(); udelay(5); send_stop(); lanai->eeprom[address] = data; DPRINTK("EEPROM 0x%04X %02X\n", address, data); } return 0; error: clock_l(); udelay(5); /* finish read */ send_stop(); printk(KERN_ERR DEV_LABEL "(itf %d): error reading EEPROM byte %d\n", lanai->number, address); return -EIO;#undef set_config1#undef clock_h#undef clock_l#undef data_h#undef data_l#undef pre_read#undef read_pin#undef send_stop}/* read a big-endian 4-byte value out of eeprom */static inline u32 eeprom_be4(const struct lanai_dev *lanai, int address){ return be32_to_cpup((u32 *) (&lanai->eeprom[address]));}/* Checksum/validate EEPROM contents */static int __init eeprom_validate(struct lanai_dev *lanai){ int i, s; u32 v; const u8 *e = lanai->eeprom;#ifdef DEBUG /* First, see if we can get an ASCIIZ string out of the copyright */ for (i = EEPROM_COPYRIGHT; i < (EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN); i++) if (e[i] < 0x20 || e[i] > 0x7E) break; if ( i != EEPROM_COPYRIGHT && i != EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN && e[i] == '\0') DPRINTK("eeprom: copyright = \"%s\"\n", (char *) &e[EEPROM_COPYRIGHT]); else DPRINTK("eeprom: copyright not found\n");#endif /* Validate checksum */ for (i = s = 0; i < EEPROM_CHECKSUM; i++) s += e[i]; s &= 0xFF; if (s != e[EEPROM_CHECKSUM]) { printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM checksum bad " "(wanted 0x%02X, got 0x%02X)\n", lanai->number, s, e[EEPROM_CHECKSUM]); return -EIO; } s ^= 0xFF; if (s != e[EEPROM_CHECKSUM_REV]) { printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM inverse checksum " "bad (wanted 0x%02X, got 0x%02X)\n", lanai->number, s, e[EEPROM_CHECKSUM_REV]); return -EIO; } /* Verify MAC address */ for (i = 0; i < 6; i++) if ((e[EEPROM_MAC + i] ^ e[EEPROM_MAC_REV + i]) != 0xFF) { printk(KERN_ERR DEV_LABEL "(itf %d) : EEPROM MAC addresses don't match " "(0x%02X, inverse 0x%02X)\n", lanai->number, e[EEPROM_MAC + i], e[EEPROM_MAC_REV + i]); return -EIO; } DPRINTK("eeprom: MAC address = %02X:%02X:%02X:%02X:%02X:%02X\n", e[EEPROM_MAC + 0], e[EEPROM_MAC + 1], e[EEPROM_MAC + 2], e[EEPROM_MAC + 3], e[EEPROM_MAC + 4], e[EEPROM_MAC + 5]); /* Verify serial number */ lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL); v = eeprom_be4(lanai, EEPROM_SERIAL_REV); if ((lanai->serialno ^ v) != 0xFFFFFFFF) { printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM serial numbers " "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, lanai->serialno, v); return -EIO; } DPRINTK("eeprom: Serial number = %d\n", lanai->serialno); /* Verify magic number */ lanai->magicno = eeprom_be4(lanai, EEPROM_MAGIC); v = eeprom_be4(lanai, EEPROM_MAGIC_REV); if ((lanai->magicno ^ v) != 0xFFFFFFFF) { printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM magic numbers " "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, lanai->magicno, v); return -EIO; } DPRINTK("eeprom: Magic number = 0x%08X\n", lanai->magicno); if (lanai->magicno != EEPROM_MAGIC_VALUE) printk(KERN_WARNING DEV_LABEL "(itf %d): warning - EEPROM " "magic not what expected (got 0x%08X, not 0x%08X)\n", lanai->number, lanai->magicno, EEPROM_MAGIC_VALUE); return 0;}#endif /* READ_EEPROM */static inline const u8 *eeprom_mac(const struct lanai_dev *lanai){ return &lanai->eeprom[EEPROM_MAC];}/* -------------------- INTERRUPT HANDLING UTILITIES: *//* Interrupt types */#define INT_STATS (0x00000002) /* Statistics counter overflow */#define INT_SOOL (0x00000004) /* SOOL changed state */#define INT_LOCD (0x00000008) /* LOCD changed state */#define INT_LED (0x00000010) /* LED (HAPPI) changed state */#define INT_GPIN (0x00000020) /* GPIN changed state */#define INT_PING (0x00000040) /* PING_COUNT fulfilled */#define INT_WAKE (0x00000080) /* Lanai wants bus */#define INT_CBR0 (0x00000100) /* CBR sched hit VCI 0 */#define INT_LOCK (0x00000200) /* Service list overflow */#define INT_MISMATCH (0x00000400) /* TX magic list mismatch */#define INT_AAL0_STR (0x00000800) /* Non-AAL5 buffer half filled */#define INT_AAL0 (0x00001000) /* Non-AAL5 data available */#define INT_SERVICE (0x00002000) /* Service list entries available */#define INT_TABORTSENT (0x00004000) /* Target abort sent by lanai */#define INT_TABORTBM (0x00008000) /* Abort rcv'd as bus master */#define INT_TIMEOUTBM (0x00010000) /* No response to bus master */#define INT_PCIPARITY (0x00020000) /* Parity error on PCI *//* Sets of the above */#define INT_ALL (0x0003FFFE) /* All interrupts */#define INT_STATUS (0x0000003C) /* Some status pin changed */#define INT_DMASHUT (0x00038000) /* DMA engine got shut down */#define INT_SEGSHUT (0x00000700) /* Segmentation got shut down */static inline u32 intr_pending(const struct lanai_dev *lanai){ return reg_read(lanai, IntStatusMasked_Reg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -