⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nicstar.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
   }#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 + -