📄 idt77252.c
字号:
case ATM_VBR: case ATM_ABR: default: return -EPROTONOSUPPORT; } vc->scq = alloc_scq(card, vc->class); if (!vc->scq) { printk("%s: can't get SCQ.\n", card->name); return -ENOMEM; } vc->scq->scd = get_free_scd(card, vc); if (vc->scq->scd == 0) { printk("%s: no SCD available.\n", card->name); free_scq(card, vc->scq); return -ENOMEM; } fill_scd(card, vc->scq, vc->class); if (set_tct(card, vc)) { printk("%s: class %d not supported.\n", card->name, qos->txtp.traffic_class); card->scd2vc[vc->scd_index] = NULL; free_scq(card, vc->scq); return -EPROTONOSUPPORT; } switch (vc->class) { case SCHED_CBR: error = idt77252_init_cbr(card, vc, vcc, qos); if (error) { card->scd2vc[vc->scd_index] = NULL; free_scq(card, vc->scq); return error; } clear_bit(VCF_IDLE, &vc->flags); writel(TCMDQ_START | vc->index, SAR_REG_TCMDQ); break; case SCHED_UBR: error = idt77252_init_ubr(card, vc, vcc, qos); if (error) { card->scd2vc[vc->scd_index] = NULL; free_scq(card, vc->scq); return error; } set_bit(VCF_IDLE, &vc->flags); break; } vc->tx_vcc = vcc; set_bit(VCF_TX, &vc->flags); return 0;}static intidt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc, struct atm_vcc *vcc, struct atm_qos *qos){ unsigned long flags; unsigned long addr; u32 rcte = 0; if (test_bit(VCF_RX, &vc->flags)) return -EBUSY; vc->rx_vcc = vcc; set_bit(VCF_RX, &vc->flags); if ((vcc->vci == 3) || (vcc->vci == 4)) return 0; flush_rx_pool(card, &vc->rcv.rx_pool); rcte |= SAR_RCTE_CONNECTOPEN; rcte |= SAR_RCTE_RAWCELLINTEN; switch (qos->aal) { case ATM_AAL0: rcte |= SAR_RCTE_RCQ; break; case ATM_AAL1: rcte |= SAR_RCTE_OAM; /* Let SAR drop Video */ break; case ATM_AAL34: rcte |= SAR_RCTE_AAL34; break; case ATM_AAL5: rcte |= SAR_RCTE_AAL5; break; default: rcte |= SAR_RCTE_RCQ; break; } if (qos->aal != ATM_AAL5) rcte |= SAR_RCTE_FBP_1; else if (qos->rxtp.max_sdu > SAR_FB_SIZE_2) rcte |= SAR_RCTE_FBP_3; else if (qos->rxtp.max_sdu > SAR_FB_SIZE_1) rcte |= SAR_RCTE_FBP_2; else if (qos->rxtp.max_sdu > SAR_FB_SIZE_0) rcte |= SAR_RCTE_FBP_1; else rcte |= SAR_RCTE_FBP_01; addr = card->rct_base + (vc->index << 2); OPRINTK("%s: writing RCT at 0x%lx\n", card->name, addr); write_sram(card, addr, rcte); spin_lock_irqsave(&card->cmd_lock, flags); writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), SAR_REG_CMD); waitfor_idle(card); spin_unlock_irqrestore(&card->cmd_lock, flags); return 0;}static intidt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci){ struct atm_vcc *walk; if (*vpi == ATM_VPI_ANY) { *vpi = 0; walk = vcc->dev->vccs; while (walk) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) { (*vpi)++; walk = vcc->dev->vccs; continue; } walk = walk->next; } } if (*vci == ATM_VCI_ANY) { *vci = ATM_NOT_RSV_VCI; walk = vcc->dev->vccs; while (walk) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) { (*vci)++; walk = vcc->dev->vccs; continue; } walk = walk->next; } } return 0;}static intidt77252_open(struct atm_vcc *vcc, short vpi, int vci){ struct atm_dev *dev = vcc->dev; struct idt77252_dev *card = dev->dev_data; struct vc_map *vc; unsigned int index; unsigned int inuse; int error; idt77252_find_vcc(vcc, &vpi, &vci); if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; if (vpi >= (1 << card->vpibits)) { printk("%s: unsupported VPI: %d\n", card->name, vpi); return -EINVAL; } if (vci >= (1 << card->vcibits)) { printk("%s: unsupported VCI: %d\n", card->name, vci); return -EINVAL; } vcc->vpi = vpi; vcc->vci = vci; set_bit(ATM_VF_ADDR, &vcc->flags); down(&card->mutex); OPRINTK("%s: opening vpi.vci: %d.%d\n", card->name, vpi, vci); switch (vcc->qos.aal) { case ATM_AAL0: case ATM_AAL1: case ATM_AAL5: break; default: printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); up(&card->mutex); return -EPROTONOSUPPORT; } index = VPCI2VC(card, vpi, vci); if (!card->vcs[index]) { card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL); if (!card->vcs[index]) { printk("%s: can't alloc vc in open()\n", card->name); up(&card->mutex); return -ENOMEM; } memset(card->vcs[index], 0, sizeof(struct vc_map)); card->vcs[index]->card = card; card->vcs[index]->index = index; spin_lock_init(&card->vcs[index]->lock); } vc = card->vcs[index]; vcc->dev_data = vc; IPRINTK("%s: idt77252_open: vc = %d (%d.%d) %s/%s (max RX SDU: %u)\n", card->name, vc->index, vcc->vpi, vcc->vci, vcc->qos.rxtp.traffic_class != ATM_NONE ? "rx" : "--", vcc->qos.txtp.traffic_class != ATM_NONE ? "tx" : "--", vcc->qos.rxtp.max_sdu); inuse = 0; if (vcc->qos.txtp.traffic_class != ATM_NONE && test_bit(VCF_TX, &vc->flags)) inuse = 1; if (vcc->qos.rxtp.traffic_class != ATM_NONE && test_bit(VCF_RX, &vc->flags)) inuse += 2; if (inuse) { printk("%s: %s vci already in use.\n", card->name, inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); up(&card->mutex); return -EADDRINUSE; } if (vcc->qos.txtp.traffic_class != ATM_NONE) { error = idt77252_init_tx(card, vc, vcc, &vcc->qos); if (error) { up(&card->mutex); return error; } } if (vcc->qos.rxtp.traffic_class != ATM_NONE) { error = idt77252_init_rx(card, vc, vcc, &vcc->qos); if (error) { up(&card->mutex); return error; } } set_bit(ATM_VF_READY, &vcc->flags); MOD_INC_USE_COUNT; up(&card->mutex); return 0;}static voididt77252_close(struct atm_vcc *vcc){ struct atm_dev *dev = vcc->dev; struct idt77252_dev *card = dev->dev_data; struct vc_map *vc = vcc->dev_data; unsigned long flags; unsigned long addr; int timeout; down(&card->mutex); IPRINTK("%s: idt77252_close: vc = %d (%d.%d)\n", card->name, vc->index, vcc->vpi, vcc->vci); clear_bit(ATM_VF_READY, &vcc->flags); if (vcc->qos.rxtp.traffic_class != ATM_NONE) { spin_lock_irqsave(&vc->lock, flags); clear_bit(VCF_RX, &vc->flags); vc->rx_vcc = NULL; spin_unlock_irqrestore(&vc->lock, flags); if ((vcc->vci == 3) || (vcc->vci == 4)) goto done; addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE; spin_lock_irqsave(&card->cmd_lock, flags); writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), SAR_REG_CMD); waitfor_idle(card); spin_unlock_irqrestore(&card->cmd_lock, flags); if (vc->rcv.rx_pool.count) { DPRINTK("%s: closing a VC with pending rx buffers.\n", card->name); recycle_rx_pool_skb(card, &vc->rcv.rx_pool); } }done: if (vcc->qos.txtp.traffic_class != ATM_NONE) { spin_lock_irqsave(&vc->lock, flags); clear_bit(VCF_TX, &vc->flags); clear_bit(VCF_IDLE, &vc->flags); clear_bit(VCF_RSV, &vc->flags); vc->tx_vcc = NULL; if (vc->estimator) { del_timer(&vc->estimator->timer); kfree(vc->estimator); vc->estimator = NULL; } spin_unlock_irqrestore(&vc->lock, flags); timeout = 5 * HZ; while (atomic_read(&vc->scq->used) > 0) { timeout = schedule_timeout(timeout); if (!timeout) break; } if (!timeout) printk("%s: SCQ drain timeout: %u used\n", card->name, atomic_read(&vc->scq->used)); writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ); clear_scd(card, vc->scq, vc->class); if (vc->class == SCHED_CBR) { clear_tst(card, vc); card->tst_free += vc->ntste; vc->ntste = 0; } card->scd2vc[vc->scd_index] = NULL; free_scq(card, vc->scq); } MOD_DEC_USE_COUNT; up(&card->mutex);}static intidt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags){ struct atm_dev *dev = vcc->dev; struct idt77252_dev *card = dev->dev_data; struct vc_map *vc = vcc->dev_data; int error = 0; down(&card->mutex); if (qos->txtp.traffic_class != ATM_NONE) { if (!test_bit(VCF_TX, &vc->flags)) { error = idt77252_init_tx(card, vc, vcc, qos); if (error) goto out; } else { switch (qos->txtp.traffic_class) { case ATM_CBR: error = idt77252_init_cbr(card, vc, vcc, qos); if (error) goto out; break; case ATM_UBR: error = idt77252_init_ubr(card, vc, vcc, qos); if (error) goto out; if (!test_bit(VCF_IDLE, &vc->flags)) { writel(TCMDQ_LACR | (vc->lacr << 16) | vc->index, SAR_REG_TCMDQ); } break; case ATM_VBR: case ATM_ABR: error = -EOPNOTSUPP; goto out; } } } if ((qos->rxtp.traffic_class != ATM_NONE) && !test_bit(VCF_RX, &vc->flags)) { error = idt77252_init_rx(card, vc, vcc, qos); if (error) goto out; } memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); set_bit(ATM_VF_HASQOS, &vcc->flags);out: up(&card->mutex); return error;}static intidt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page){ struct idt77252_dev *card = dev->dev_data; int i, left; left = (int) *pos; if (!left--) return sprintf(page, "IDT77252 Interrupts:\n"); if (!left--) return sprintf(page, "TSIF: %lu\n", card->irqstat[15]); if (!left--) return sprintf(page, "TXICP: %lu\n", card->irqstat[14]); if (!left--) return sprintf(page, "TSQF: %lu\n", card->irqstat[12]); if (!left--) return sprintf(page, "TMROF: %lu\n", card->irqstat[11]); if (!left--) return sprintf(page, "PHYI: %lu\n", card->irqstat[10]); if (!left--) return sprintf(page, "FBQ3A: %lu\n", card->irqstat[8]); if (!left--) return sprintf(page, "FBQ2A: %lu\n", card->irqstat[7]); if (!left--) return sprintf(page, "RSQF: %lu\n", card->irqstat[6]); if (!left--) return sprintf(page, "EPDU: %lu\n", card->irqstat[5]); if (!left--) return sprintf(page, "RAWCF: %lu\n", card->irqstat[4]); if (!left--) return sprintf(page, "FBQ1A: %lu\n", card->irqstat[3]); if (!left--) return sprintf(page, "FBQ0A: %lu\n", card->irqstat[2]); if (!left--) return sprintf(page, "RSQAF: %lu\n", card->irqstat[1]); if (!left--) return sprintf(page, "IDT77252 Transmit Connection Table:\n"); for (i = 0; i < card->tct_size; i++) { unsigned long tct; struct atm_vcc *vcc; struct vc_map *vc; char *p; vc = card->vcs[i]; if (!vc) continue; vcc = NULL; if (vc->tx_vcc) vcc = vc->tx_vcc; if (!vcc) continue; if (left--) continue; p = page; p += sprintf(p, " %4u: %u.%u: ", i, vcc->vpi, vcc->vci); tct = (unsigned long) (card->tct_base + i * SAR_SRAM_TCT_SIZE); for (i = 0; i < 8; i++) p += sprintf(p, " %08x", read_sram(card, tct + i)); p += sprintf(p, "\n"); return p - page; } return 0;}/*****************************************************************************//* *//* Interrupt handler *//* *//*****************************************************************************/static voididt77252_collect_stat(struct idt77252_dev *card){ u32 cdc, vpec, icc; cdc = readl(SAR_REG_CDC); vpec = readl(SAR_REG_VPEC); icc = readl(SAR_REG_ICC);#ifdef NOTDEF printk("%s:", card->name); if (cdc & 0x7f0000) { char *s = ""; printk(" ["); if (cdc & (1 << 22)) { printk("%sRM ID", s); s = " | "; } if (cdc & (1 << 21)) { printk("%sCON TAB", s); s = " | "; } if (cdc & (1 << 20)) { printk("%sNO FB", s); s = " | "; } if (cdc & (1 << 19)) { printk("%sOAM CRC", s); s = " | "; } if (cdc & (1 << 18)) { printk("%sRM CRC", s); s = " | "; } if (cdc & (1 << 17)) { printk("%sRM FIFO", s); s = " | "; } if (cdc & (1 << 16)) { printk("%sRX FIFO", s); s = " | "; } printk("]"); } printk(" CDC %04x, VPEC %04x, ICC: %04x\n", cdc & 0xffff, vpec & 0xffff, icc & 0xffff);#endif}static voididt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs){ struct idt77252_dev *card = dev_id; u32 stat; stat = readl(SAR_REG_STAT) & 0xffff; if (!stat) /* no interrupt for us */ return; if (test_and_set_bit(IDT77252_BIT_INTERRUPT, &card->flags)) { printk("%s: Re-entering irq_handler()\n", card->name); goto out; } writel(stat, SAR_REG_STAT); /* reset interrupt */ if (stat & SAR_STAT_TSIF) { /* entry written to TSQ */ INTPRINTK("%s: TSIF\n", card->name); card->irqstat[15]++; idt77252_tx(card); } if (stat & SAR_STAT_TXICP) { /* Incomplete CS-PDU has */ INTPRINTK("%s: TXICP\n", card->name); card->irqstat[14]++;#ifdef CONFIG_ATM_IDT77252_DEBUG idt77252_tx_dump(card);#endif } if (stat & SAR_STAT_TSQF) { /* TSQ 7/8 full */ INTPRINTK("%s: TSQF\n", card->name); card->irqstat[12]++; idt77252_tx(card); } if (stat & SAR_STAT_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -