📄 nicstar.c
字号:
/* Receive Status Queue is full */ if (stat_r & NS_STAT_RSQF) { writel(NS_STAT_RSQF, card->membase + STAT); printk("nicstar%d: RSQ full.\n", card->index); process_rsq(card); } /* Complete CS-PDU received */ if (stat_r & NS_STAT_EOPDU) { RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); process_rsq(card); writel(NS_STAT_EOPDU, card->membase + STAT); } /* Raw cell received */ if (stat_r & NS_STAT_RAWCF) { writel(NS_STAT_RAWCF, card->membase + STAT);#ifndef RCQ_SUPPORT printk("nicstar%d: Raw cell received and no support yet...\n", card->index);#endif /* RCQ_SUPPORT */ /* NOTE: the following procedure may keep a raw cell pending untill the next interrupt. As this preliminary support is only meant to avoid buffer leakage, this is not an issue. */ while (readl(card->membase + RAWCT) != card->rawch) { ns_rcqe *rawcell; rawcell = (ns_rcqe *) bus_to_virt(card->rawch); if (ns_rcqe_islast(rawcell)) { struct sk_buff *oldbuf; oldbuf = card->rcbuf; card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell); card->rawch = (u32) virt_to_bus(card->rcbuf->data); recycle_rx_buf(card, oldbuf); } else card->rawch += NS_RCQE_SIZE; } } /* Small buffer queue is empty */ if (stat_r & NS_STAT_SFBQE) { int i; struct sk_buff *sb; writel(NS_STAT_SFBQE, card->membase + STAT); printk("nicstar%d: Small free buffer queue empty.\n", card->index); for (i = 0; i < card->sbnr.min; i++) { sb = alloc_skb(NS_SMSKBSIZE, GFP_ATOMIC); if (sb == NULL) { writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); card->efbie = 0; break; } skb_queue_tail(&card->sbpool.queue, sb); skb_reserve(sb, NS_AAL0_HEADER); push_rxbufs(card, BUF_SM, (u32) sb, (u32) virt_to_bus(sb->data), 0, 0); } card->sbfqc = i; process_rsq(card); } /* Large buffer queue empty */ if (stat_r & NS_STAT_LFBQE) { int i; struct sk_buff *lb; writel(NS_STAT_LFBQE, card->membase + STAT); printk("nicstar%d: Large free buffer queue empty.\n", card->index); for (i = 0; i < card->lbnr.min; i++) { lb = alloc_skb(NS_LGSKBSIZE, GFP_ATOMIC); if (lb == NULL) { writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG); card->efbie = 0; break; } skb_queue_tail(&card->lbpool.queue, lb); skb_reserve(lb, NS_SMBUFSIZE); push_rxbufs(card, BUF_LG, (u32) lb, (u32) virt_to_bus(lb->data), 0, 0); } card->lbfqc = i; process_rsq(card); } /* Receive Status Queue is 7/8 full */ if (stat_r & NS_STAT_RSQAF) { writel(NS_STAT_RSQAF, card->membase + STAT); RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); process_rsq(card); } spin_unlock_irqrestore(&card->int_lock, flags); PRINTK("nicstar%d: end of interrupt service\n", card->index);}static int ns_open(struct atm_vcc *vcc, short vpi, int vci){ ns_dev *card; vc_map *vc; int error; unsigned long tmpl, modl; int tcr, tcra; /* target cell rate, and absolute value */ int n = 0; /* Number of entries in the TST. Initialized to remove the compiler warning. */ u32 u32d[4]; int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler warning. How I wish compilers were clever enough to tell which variables can truly be used uninitialized... */ int inuse; /* tx or rx vc already in use by another vcc */ card = (ns_dev *) vcc->dev->dev_data; PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci); if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { PRINTK("nicstar%d: unsupported AAL.\n", card->index); return -EINVAL; } if ((error = atm_find_ci(vcc, &vpi, &vci))) { PRINTK("nicstar%d: error in atm_find_ci().\n", card->index); return error; } vc = &(card->vcmap[vpi << card->vcibits | vci]); vcc->vpi = vpi; vcc->vci = vci; vcc->dev_data = vc; inuse = 0; if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) inuse = 1; if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) inuse += 2; if (inuse) { printk("nicstar%d: %s vci already in use.\n", card->index, inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); return -EINVAL; } set_bit(ATM_VF_ADDR,&vcc->flags); /* NOTE: You are not allowed to modify an open connection's QOS. To change that, remove the ATM_VF_PARTIAL flag checking. There may be other changes needed to do that. */ if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { scq_info *scq; set_bit(ATM_VF_PARTIAL,&vcc->flags); if (vcc->qos.txtp.traffic_class == ATM_CBR) { /* Check requested cell rate and availability of SCD */ if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 && vcc->qos.txtp.min_pcr == 0) { PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", card->index); clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } tcr = atm_pcr_goal(&(vcc->qos.txtp)); tcra = tcr >= 0 ? tcr : -tcr; PRINTK("nicstar%d: target cell rate = %d.\n", card->index, vcc->qos.txtp.max_pcr); tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES; modl = tmpl % card->max_pcr; n = (int)(tmpl / card->max_pcr); if (tcr > 0) { if (modl > 0) n++; } else if (tcr == 0) { if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0) { PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index); clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } } if (n == 0) { printk("nicstar%d: selected bandwidth < granularity.\n", card->index); clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } if (n > (card->tst_free_entries - NS_TST_RESERVED)) { PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index); clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -EINVAL; } else card->tst_free_entries -= n; XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n); for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) { if (card->scd2vc[frscdi] == NULL) { card->scd2vc[frscdi] = vc; break; } } if (frscdi == NS_FRSCD_NUM) { PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index); card->tst_free_entries += n; clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -EBUSY; } vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); if (scq == (scq_info *) NULL) { PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); card->scd2vc[frscdi] = NULL; card->tst_free_entries += n; clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags); return -ENOMEM; } vc->scq = scq; u32d[0] = (u32) virt_to_bus(scq->base); u32d[1] = (u32) 0x00000000; u32d[2] = (u32) 0xffffffff; u32d[3] = (u32) 0x00000000; ns_write_sram(card, vc->cbr_scd, u32d, 4); fill_tst(card, n, vc); } else /* not CBR */ { vc->cbr_scd = 0x00000000; vc->scq = card->scq0; } if (vcc->qos.txtp.traffic_class != ATM_NONE) { vc->tx = 1; vc->tx_vcc = vcc; vc->tbd_count = 0; } if (vcc->qos.rxtp.traffic_class != ATM_NONE) { u32 status; vc->rx = 1; vc->rx_vcc = vcc; vc->rx_iov = NULL; /* Open the connection in hardware */ if (vcc->qos.aal == ATM_AAL5) status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; else /* vcc->qos.aal == ATM_AAL0 */ status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;#ifdef RCQ_SUPPORT status |= NS_RCTE_RAWCELLINTEN;#endif /* RCQ_SUPPORT */ ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) * NS_RCT_ENTRY_SIZE, &status, 1); } } set_bit(ATM_VF_READY,&vcc->flags); return 0;}static void ns_close(struct atm_vcc *vcc){ vc_map *vc; ns_dev *card; u32 data; int i; vc = vcc->dev_data; card = vcc->dev->dev_data; PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, (int) vcc->vpi, vcc->vci); clear_bit(ATM_VF_READY,&vcc->flags); if (vcc->qos.rxtp.traffic_class != ATM_NONE) { u32 addr; unsigned long flags; addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; ns_grab_res_lock(card, flags); while(CMD_BUSY(card)); writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD); spin_unlock_irqrestore(&card->res_lock, flags); vc->rx = 0; if (vc->rx_iov != NULL) { struct sk_buff *iovb; u32 stat; stat = readl(card->membase + STAT); card->sbfqc = ns_stat_sfbqc_get(stat); card->lbfqc = ns_stat_lfbqc_get(stat); PRINTK("nicstar%d: closing a VC with pending rx buffers.\n", card->index); iovb = vc->rx_iov; recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, ATM_SKB(iovb)->iovcnt); ATM_SKB(iovb)->iovcnt = 0; ATM_SKB(iovb)->vcc = NULL; ns_grab_int_lock(card, flags); recycle_iov_buf(card, iovb); spin_unlock_irqrestore(&card->int_lock, flags); vc->rx_iov = NULL; } } if (vcc->qos.txtp.traffic_class != ATM_NONE) { vc->tx = 0; } if (vcc->qos.txtp.traffic_class == ATM_CBR) { unsigned long flags; ns_scqe *scqep; scq_info *scq; scq = vc->scq; for (;;) { ns_grab_scq_lock(card, scq, flags); scqep = scq->next; if (scqep == scq->base) scqep = scq->last; else scqep--; if (scqep == scq->tail) { spin_unlock_irqrestore(&scq->lock, flags); break; } /* If the last entry is not a TSR, place one in the SCQ in order to be able to completely drain it and then close. */ if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) { ns_scqe tsr; u32 scdi, scqi; u32 data; int index; tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; scqi = scq->next - scq->base; tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); tsr.word_3 = 0x00000000; tsr.word_4 = 0x00000000; *scq->next = tsr; index = (int) scqi; scq->skb[index] = NULL; if (scq->next == scq->last) scq->next = scq->base; else scq->next++; data = (u32) virt_to_bus(scq->next); ns_write_sram(card, scq->scd, &data, 1); } spin_unlock_irqrestore(&scq->lock, flags); schedule(); } /* Free all TST entries */ data = NS_TST_OPCODE_VARIABLE; for (i = 0; i < NS_TST_NUM_ENTRIES; i++) { if (card->tste2vc[i] == vc) { ns_write_sram(card, card->tst_addr + i, &data, 1); card->tste2vc[i] = NULL; card->tst_free_entries++; } } card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; free_scq(vc->scq, vcc); } vcc->dev_data = NULL; clear_bit(ATM_VF_PARTIAL,&vcc->flags); clear_bit(ATM_VF_ADDR,&vcc->flags);#ifdef RX_DEBUG { u32 stat, cfg; stat = readl(card->membase + STAT); cfg = readl(card->membase + CFG); printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n", (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last, readl(card->membase + TSQT)); printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n", (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last, readl(card->membase + RSQT)); printk("Empty free buffer queue interrupt %s \n", card->efbie ? "enabled" : "disabled"); printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", ns_stat_sfbqc_get(stat), card->sbpool.count, ns_stat_lfbqc_get(stat), card->lbpool.count); printk("hbpool.count = %d iovpool.count = %d \n", card->hbpool.count, card->iovpool.count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -