nicstar.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,232 行 · 第 1/5 页

C
2,232
字号
   card->atmdev->ci_range.vci_bits = card->vcibits;   card->atmdev->link_rate = card->max_pcr;   card->atmdev->phy = NULL;#ifdef CONFIG_ATM_NICSTAR_USE_SUNI   if (card->max_pcr == ATM_OC3_PCR)      suni_init(card->atmdev);#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105   if (card->max_pcr == ATM_25_PCR)      idt77105_init(card->atmdev);#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */   if (card->atmdev->phy && card->atmdev->phy->start)      card->atmdev->phy->start(card->atmdev);   writel(NS_CFG_RXPATH |          NS_CFG_SMBUFSIZE |          NS_CFG_LGBUFSIZE |          NS_CFG_EFBIE |          NS_CFG_RSQSIZE |          NS_CFG_VPIBITS |          ns_cfg_rctsize |          NS_CFG_RXINT_NODELAY |          NS_CFG_RAWIE |		/* Only enabled if RCQ_SUPPORT */          NS_CFG_RSQAFIE |          NS_CFG_TXEN |          NS_CFG_TXIE |          NS_CFG_TSQFIE_OPT |		/* Only enabled if ENABLE_TSQFIE */           NS_CFG_PHYIE,          card->membase + CFG);   num_cards++;   return error;}static void __devinit ns_init_card_error(ns_dev *card, int error){   if (error >= 17)   {      writel(0x00000000, card->membase + CFG);   }   if (error >= 16)   {      struct sk_buff *iovb;      while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)         dev_kfree_skb_any(iovb);   }   if (error >= 15)   {      struct sk_buff *sb;      while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)         dev_kfree_skb_any(sb);      free_scq(card->scq0, NULL);   }   if (error >= 14)   {      struct sk_buff *lb;      while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)         dev_kfree_skb_any(lb);   }   if (error >= 13)   {      struct sk_buff *hb;      while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)         dev_kfree_skb_any(hb);   }   if (error >= 12)   {      kfree(card->rsq.org);   }   if (error >= 11)   {      kfree(card->tsq.org);   }   if (error >= 10)   {      free_irq(card->pcidev->irq, card);   }   if (error >= 4)   {      iounmap((void *) card->membase);   }   if (error >= 3)   {      pci_disable_device(card->pcidev);      kfree(card);   }}static scq_info *get_scq(int size, u32 scd){   scq_info *scq;   int i;   if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)      return (scq_info *) NULL;   scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);   if (scq == (scq_info *) NULL)      return (scq_info *) NULL;   scq->org = kmalloc(2 * size, GFP_KERNEL);   if (scq->org == NULL)   {      kfree(scq);      return (scq_info *) NULL;   }   scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *                                          (size / NS_SCQE_SIZE), GFP_KERNEL);   if (scq->skb == (struct sk_buff **) NULL)   {      kfree(scq->org);      kfree(scq);      return (scq_info *) NULL;   }   scq->num_entries = size / NS_SCQE_SIZE;   scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);   scq->next = scq->base;   scq->last = scq->base + (scq->num_entries - 1);   scq->tail = scq->last;   scq->scd = scd;   scq->num_entries = size / NS_SCQE_SIZE;   scq->tbd_count = 0;   init_waitqueue_head(&scq->scqfull_waitq);   scq->full = 0;   spin_lock_init(&scq->lock);   for (i = 0; i < scq->num_entries; i++)      scq->skb[i] = NULL;   return scq;}/* For variable rate SCQ vcc must be NULL */static void free_scq(scq_info *scq, struct atm_vcc *vcc){   int i;   if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)      for (i = 0; i < scq->num_entries; i++)      {         if (scq->skb[i] != NULL)	 {            vcc = ATM_SKB(scq->skb[i])->vcc;            if (vcc->pop != NULL)	       vcc->pop(vcc, scq->skb[i]);	    else               dev_kfree_skb_any(scq->skb[i]);         }      }   else /* vcc must be != NULL */   {      if (vcc == NULL)      {         printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");         for (i = 0; i < scq->num_entries; i++)            dev_kfree_skb_any(scq->skb[i]);      }      else         for (i = 0; i < scq->num_entries; i++)         {            if (scq->skb[i] != NULL)            {               if (vcc->pop != NULL)                  vcc->pop(vcc, scq->skb[i]);               else                  dev_kfree_skb_any(scq->skb[i]);            }         }   }   kfree(scq->skb);   kfree(scq->org);   kfree(scq);}/* The handles passed must be pointers to the sk_buff containing the small   or large buffer(s) cast to u32. */static void push_rxbufs(ns_dev *card, u32 type, u32 handle1, u32 addr1,                       u32 handle2, u32 addr2){   u32 stat;   unsigned long flags;   #ifdef GENERAL_DEBUG   if (!addr1)      printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index);#endif /* GENERAL_DEBUG */   stat = readl(card->membase + STAT);   card->sbfqc = ns_stat_sfbqc_get(stat);   card->lbfqc = ns_stat_lfbqc_get(stat);   if (type == BUF_SM)   {      if (!addr2)      {         if (card->sm_addr)	 {	    addr2 = card->sm_addr;	    handle2 = card->sm_handle;	    card->sm_addr = 0x00000000;	    card->sm_handle = 0x00000000;	 }	 else /* (!sm_addr) */	 {	    card->sm_addr = addr1;	    card->sm_handle = handle1;	 }      }         }   else /* type == BUF_LG */   {      if (!addr2)      {         if (card->lg_addr)	 {	    addr2 = card->lg_addr;	    handle2 = card->lg_handle;	    card->lg_addr = 0x00000000;	    card->lg_handle = 0x00000000;	 }	 else /* (!lg_addr) */	 {	    card->lg_addr = addr1;	    card->lg_handle = handle1;	 }      }         }   if (addr2)   {      if (type == BUF_SM)      {         if (card->sbfqc >= card->sbnr.max)         {            skb_unlink((struct sk_buff *) handle1);            dev_kfree_skb_any((struct sk_buff *) handle1);            skb_unlink((struct sk_buff *) handle2);            dev_kfree_skb_any((struct sk_buff *) handle2);            return;         }	 else            card->sbfqc += 2;      }      else /* (type == BUF_LG) */      {         if (card->lbfqc >= card->lbnr.max)         {            skb_unlink((struct sk_buff *) handle1);            dev_kfree_skb_any((struct sk_buff *) handle1);            skb_unlink((struct sk_buff *) handle2);            dev_kfree_skb_any((struct sk_buff *) handle2);            return;         }         else            card->lbfqc += 2;      }      ns_grab_res_lock(card, flags);      while (CMD_BUSY(card));      writel(addr2, card->membase + DR3);      writel(handle2, card->membase + DR2);      writel(addr1, card->membase + DR1);      writel(handle1, card->membase + DR0);      writel(NS_CMD_WRITE_FREEBUFQ | (u32) type, card->membase + CMD);       spin_unlock_irqrestore(&card->res_lock, flags);      XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,              (type == BUF_SM ? "small" : "large"), addr1, addr2);   }   if (!card->efbie && card->sbfqc >= card->sbnr.min &&       card->lbfqc >= card->lbnr.min)   {      card->efbie = 1;      writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG);   }   return;}static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs){   u32 stat_r;   ns_dev *card;   struct atm_dev *dev;   unsigned long flags;   card = (ns_dev *) dev_id;   dev = card->atmdev;   card->intcnt++;   PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);   ns_grab_int_lock(card, flags);      stat_r = readl(card->membase + STAT);   /* Transmit Status Indicator has been written to T. S. Queue */   if (stat_r & NS_STAT_TSIF)   {      TXPRINTK("nicstar%d: TSI interrupt\n", card->index);      process_tsq(card);      writel(NS_STAT_TSIF, card->membase + STAT);   }      /* Incomplete CS-PDU has been transmitted */   if (stat_r & NS_STAT_TXICP)   {      writel(NS_STAT_TXICP, card->membase + STAT);      TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",               card->index);   }      /* Transmit Status Queue 7/8 full */   if (stat_r & NS_STAT_TSQF)   {      writel(NS_STAT_TSQF, card->membase + STAT);      PRINTK("nicstar%d: TSQ full.\n", card->index);      process_tsq(card);   }      /* Timer overflow */   if (stat_r & NS_STAT_TMROF)   {      writel(NS_STAT_TMROF, card->membase + STAT);      PRINTK("nicstar%d: Timer overflow.\n", card->index);   }      /* PHY device interrupt signal active */   if (stat_r & NS_STAT_PHYI)   {      writel(NS_STAT_PHYI, card->membase + STAT);      PRINTK("nicstar%d: PHY interrupt.\n", card->index);      if (dev->phy && dev->phy->interrupt) {         dev->phy->interrupt(dev);      }   }   /* Small Buffer Queue is full */   if (stat_r & NS_STAT_SFBQF)   {      writel(NS_STAT_SFBQF, card->membase + STAT);      printk("nicstar%d: Small free buffer queue is full.\n", card->index);   }      /* Large Buffer Queue is full */   if (stat_r & NS_STAT_LFBQF)   {      writel(NS_STAT_LFBQF, card->membase + STAT);      printk("nicstar%d: Large free buffer queue is full.\n", card->index);   }   /* 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 until 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 = dev_alloc_skb(NS_SMSKBSIZE);         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",

⌨️ 快捷键说明

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