nicstar.c

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

C
2,241
字号
      printk("nicstar%d: Large free buffer queue empty.\n",             card->index);      for (i = 0; i < card->lbnr.min; i++)      {         lb = dev_alloc_skb(NS_LGSKBSIZE);         if (lb == NULL)         {            writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);            card->efbie = 0;            break;         }         NS_SKB_CB(lb)->buf_type = BUF_LG;         skb_queue_tail(&card->lbpool.queue, lb);         skb_reserve(lb, NS_SMBUFSIZE);         push_rxbufs(card, lb);      }      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);   return IRQ_HANDLED;}static int ns_open(struct atm_vcc *vcc){   ns_dev *card;   vc_map *vc;   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 */   short vpi = vcc->vpi;   int vci = vcc->vci;   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;   }   vc = &(card->vcmap[vpi << card->vcibits | 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 == 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 if (vcc->qos.txtp.traffic_class == ATM_UBR)      {         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,	                       NS_SKB(iovb)->iovcnt);         NS_SKB(iovb)->iovcnt = 0;         NS_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);   }   /* remove all references to vcc before deleting it */   if (vcc->qos.txtp.traffic_class != ATM_NONE)   {     unsigned long flags;     scq_info *scq = card->scq0;     ns_grab_scq_lock(card, scq, flags);     for(i = 0; i < scq->num_entries; i++) {       if(scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {        ATM_SKB(scq->skb[i])->vcc = NULL;	atm_return(vcc, scq->skb[i]->truesize);        PRINTK("nicstar: deleted pending vcc mapping\n");       }     }     spin_unlock_irqrestore(&scq->lock, flags);   }   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);   }#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;

⌨️ 快捷键说明

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