nicstar.c

来自「linux 内核源代码」· C语言 代码 · 共 2,241 行 · 第 1/5 页

C
2,241
字号
   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 (skb_shinfo(skb)->nr_frags != 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 && 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;   do {      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++;   } while (ns_rsqe_valid(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: SDU received on non-rx vc %d.%d.\n",             card->index, vpi, vci);      recycle_rx_buf(card, skb);      return;   }   vcc = vc->rx_vcc;   if (vcc->qos.aal == ATM_AAL0)   {      struct sk_buff *sb;      unsigned char *cell;      int i;      cell = skb->data;      for (i = ns_rsqe_cellcount(rsqe); i; i--)      {         if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL)         {            printk("nicstar%d: Can't allocate buffers for aal0.\n",                   card->index);            atomic_add(i,&vcc->stats->rx_drop);            break;         }         if (!atm_charge(vcc, sb->truesize))         {            RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",                     card->index);            atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */            dev_kfree_skb_any(sb);            break;         }         /* Rebuild the header */         *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |                               (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);         if (i == 1 && ns_rsqe_eopdu(rsqe))            *((u32 *) sb->data) |= 0x00000002;         skb_put(sb, NS_AAL0_HEADER);         memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);         skb_put(sb, ATM_CELL_PAYLOAD);         ATM_SKB(sb)->vcc = vcc;	 __net_timestamp(sb);         vcc->push(vcc, sb);         atomic_inc(&vcc->stats->rx);         cell += ATM_CELL_PAYLOAD;      }      recycle_rx_buf(card, skb);      return;   }   /* To reach this point, the AAL layer can only be AAL5 */   if ((iovb = vc->rx_iov) == NULL)   {      iovb = skb_dequeue(&(card->iovpool.queue));      if (iovb == NULL)		/* No buffers in the queue */      {         iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);	 if (iovb == NULL)	 {	    printk("nicstar%d: Out of iovec buffers.\n", card->index);            atomic_inc(&vcc->stats->rx_drop);            recycle_rx_buf(card, skb);            return;	 }         NS_SKB_CB(iovb)->buf_type = BUF_NONE;      }      else        

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?