📄 nicstar.c
字号:
}#endif /* RX_DEBUG */}static void fill_tst(ns_dev *card, int n, vc_map *vc){ u32 new_tst; unsigned long cl; int e, r; u32 data; /* It would be very complicated to keep the two TSTs synchronized while assuring that writes are only made to the inactive TST. So, for now I will use only one TST. If problems occur, I will change this again */ new_tst = card->tst_addr; /* Fill procedure */ for (e = 0; e < NS_TST_NUM_ENTRIES; e++) { if (card->tste2vc[e] == NULL) break; } if (e == NS_TST_NUM_ENTRIES) { printk("nicstar%d: No free TST entries found. \n", card->index); return; } r = n; cl = NS_TST_NUM_ENTRIES; data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); while (r > 0) { if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) { card->tste2vc[e] = vc; ns_write_sram(card, new_tst + e, &data, 1); cl -= NS_TST_NUM_ENTRIES; r--; } if (++e == NS_TST_NUM_ENTRIES) { e = 0; } cl += n; } /* End of fill procedure */ data = ns_tste_make(NS_TST_OPCODE_END, new_tst); ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); card->tst_addr = new_tst;}static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb){ ns_dev *card; vc_map *vc; scq_info *scq; unsigned long buflen; ns_scqe scqe; u32 flags; /* TBD flags, not CPU flags */ card = vcc->dev->dev_data; TXPRINTK("nicstar%d: ns_send() called.\n", card->index); if ((vc = (vc_map *) vcc->dev_data) == NULL) { printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } if (!vc->tx) { printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } if (ATM_SKB(skb)->iovcnt != 0) { printk("nicstar%d: No scatter-gather yet.\n", card->index); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EINVAL; } ATM_SKB(skb)->vcc = vcc; if (vcc->qos.aal == ATM_AAL5) { buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ flags = NS_TBD_AAL5; scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data)); scqe.word_3 = cpu_to_le32((u32) skb->len); scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0); flags |= NS_TBD_EOPDU; } else /* (vcc->qos.aal == ATM_AAL0) */ { buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ flags = NS_TBD_AAL0; scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER); scqe.word_3 = cpu_to_le32(0x00000000); if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ flags |= NS_TBD_EOPDU; scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); /* Force the VPI/VCI to be the same as in VCC struct */ scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK); } if (vcc->qos.txtp.traffic_class == ATM_CBR) { scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); scq = ((vc_map *) vcc->dev_data)->scq; } else { scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); scq = card->scq0; } if (push_scqe(card, vc, scq, &scqe, skb) != 0) { atomic_inc(&vcc->stats->tx_err); dev_kfree_skb_any(skb); return -EIO; } atomic_inc(&vcc->stats->tx); return 0;}static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd, struct sk_buff *skb){ unsigned long flags; ns_scqe tsr; u32 scdi, scqi; int scq_is_vbr; u32 data; int index; ns_grab_scq_lock(card, scq, flags); while (scq->tail == scq->next) { if (in_interrupt()) { spin_unlock_irqrestore(&scq->lock, flags); printk("nicstar%d: Error pushing TBD.\n", card->index); return 1; } scq->full = 1; spin_unlock_irqrestore(&scq->lock, flags); interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); ns_grab_scq_lock(card, scq, flags); if (scq->full) { spin_unlock_irqrestore(&scq->lock, flags); printk("nicstar%d: Timeout pushing TBD.\n", card->index); return 1; } } *scq->next = *tbd; index = (int) (scq->next - scq->base); scq->skb[index] = skb; XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n", card->index, (u32) skb, index); XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), (u32) scq->next); if (scq->next == scq->last) scq->next = scq->base; else scq->next++; vc->tbd_count++; if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) { scq->tbd_count++; scq_is_vbr = 1; } else scq_is_vbr = 0; if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ) { int has_run = 0; while (scq->tail == scq->next) { if (in_interrupt()) { data = (u32) virt_to_bus(scq->next); ns_write_sram(card, scq->scd, &data, 1); spin_unlock_irqrestore(&scq->lock, flags); printk("nicstar%d: Error pushing TSR.\n", card->index); return 0; } scq->full = 1; if (has_run++) break; spin_unlock_irqrestore(&scq->lock, flags); interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT); ns_grab_scq_lock(card, scq, flags); } if (!scq->full) { tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); if (scq_is_vbr) scdi = NS_TSR_SCDISVBR; else 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; XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n", card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4), (u32) scq->next); if (scq->next == scq->last) scq->next = scq->base; else scq->next++; vc->tbd_count = 0; scq->tbd_count = 0; } else PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index); } data = (u32) virt_to_bus(scq->next); ns_write_sram(card, scq->scd, &data, 1); spin_unlock_irqrestore(&scq->lock, flags); return 0;}static void process_tsq(ns_dev *card){ u32 scdi; scq_info *scq; ns_tsi *previous = NULL, *one_ahead, *two_ahead; int serviced_entries; /* flag indicating at least on entry was serviced */ serviced_entries = 0; if (card->tsq.next == card->tsq.last) one_ahead = card->tsq.base; else one_ahead = card->tsq.next + 1; if (one_ahead == card->tsq.last) two_ahead = card->tsq.base; else two_ahead = one_ahead + 1; while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || !ns_tsi_isempty(two_ahead)) /* At most two empty, as stated in the 77201 errata */ { serviced_entries = 1; /* Skip the one or two possible empty entries */ while (ns_tsi_isempty(card->tsq.next)) { if (card->tsq.next == card->tsq.last) card->tsq.next = card->tsq.base; else card->tsq.next++; } if (!ns_tsi_tmrof(card->tsq.next)) { scdi = ns_tsi_getscdindex(card->tsq.next); if (scdi == NS_TSI_SCDISVBR) scq = card->scq0; else { if (card->scd2vc[scdi] == NULL) { printk("nicstar%d: could not find VC from SCD index.\n", card->index); ns_tsi_init(card->tsq.next); return; } scq = card->scd2vc[scdi]->scq; } drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); scq->full = 0; wake_up_interruptible(&(scq->scqfull_waitq)); } ns_tsi_init(card->tsq.next); previous = card->tsq.next; if (card->tsq.next == card->tsq.last) card->tsq.next = card->tsq.base; else card->tsq.next++; if (card->tsq.next == card->tsq.last) one_ahead = card->tsq.base; else one_ahead = card->tsq.next + 1; if (one_ahead == card->tsq.last) two_ahead = card->tsq.base; else two_ahead = one_ahead + 1; } if (serviced_entries) { writel((((u32) previous) - ((u32) card->tsq.base)), card->membase + TSQH); }}static void drain_scq(ns_dev *card, scq_info *scq, int pos){ struct atm_vcc *vcc; struct sk_buff *skb; int i; unsigned long flags; XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n", card->index, (u32) scq, pos); if (pos >= scq->num_entries) { printk("nicstar%d: Bad index on drain_scq().\n", card->index); return; } ns_grab_scq_lock(card, scq, flags); i = (int) (scq->tail - scq->base); if (++i == scq->num_entries) i = 0; while (i != pos) { skb = scq->skb[i]; XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n", card->index, (u32) skb, i); if (skb != NULL) { vcc = ATM_SKB(skb)->vcc; if (vcc->pop != NULL) { vcc->pop(vcc, skb); } else { dev_kfree_skb_irq(skb); } scq->skb[i] = NULL; } if (++i == scq->num_entries) i = 0; } scq->tail = scq->base + pos; spin_unlock_irqrestore(&scq->lock, flags);}static void process_rsq(ns_dev *card){ ns_rsqe *previous; if (!ns_rsqe_valid(card->rsq.next)) return; while (ns_rsqe_valid(card->rsq.next)) { dequeue_rx(card, card->rsq.next); ns_rsqe_init(card->rsq.next); previous = card->rsq.next; if (card->rsq.next == card->rsq.last) card->rsq.next = card->rsq.base; else card->rsq.next++; } writel((((u32) previous) - ((u32) card->rsq.base)), card->membase + RSQH);}static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe){ u32 vpi, vci; vc_map *vc; struct sk_buff *iovb; struct iovec *iov; struct atm_vcc *vcc; struct sk_buff *skb; unsigned short aal5_len; int len; u32 stat; stat = readl(card->membase + STAT); card->sbfqc = ns_stat_sfbqc_get(stat); card->lbfqc = ns_stat_lfbqc_get(stat); skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle); vpi = ns_rsqe_vpi(rsqe); vci = ns_rsqe_vci(rsqe); if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) { printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", card->index, vpi, vci); recycle_rx_buf(card, skb); return; } vc = &(card->vcmap[vpi << card->vcibits | vci]); if (!vc->rx) { RXPRINTK("nicstar%d:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -