nicstar.c
来自「linux 内核源代码」· C语言 代码 · 共 2,241 行 · 第 1/5 页
C
2,241 行
#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(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 NULL; scq = kmalloc(sizeof(scq_info), GFP_KERNEL); if (scq == NULL) return NULL; scq->org = kmalloc(2 * size, GFP_KERNEL); if (scq->org == NULL) { kfree(scq); return NULL; } scq->skb = kmalloc(sizeof(struct sk_buff *) * (size / NS_SCQE_SIZE), GFP_KERNEL); if (scq->skb == NULL) { kfree(scq->org); kfree(scq); return 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, struct sk_buff *skb){ struct ns_skb_cb *cb = NS_SKB_CB(skb); u32 handle1, addr1; u32 handle2, addr2; u32 stat; unsigned long flags; /* *BARF* */ handle2 = addr2 = 0; handle1 = (u32)skb; addr1 = (u32)virt_to_bus(skb->data);#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 (cb->buf_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 /* buf_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 (cb->buf_type == BUF_SM) { if (card->sbfqc >= card->sbnr.max) { skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue); dev_kfree_skb_any((struct sk_buff *) handle1); skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue); dev_kfree_skb_any((struct sk_buff *) handle2); return; } else card->sbfqc += 2; } else /* (buf_type == BUF_LG) */ { if (card->lbfqc >= card->lbnr.max) { skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue); dev_kfree_skb_any((struct sk_buff *) handle1); skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue); 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 | cb->buf_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, (cb->buf_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){ 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; } NS_SKB_CB(sb)->buf_type = BUF_SM; skb_queue_tail(&card->sbpool.queue, sb); skb_reserve(sb, NS_AAL0_HEADER); push_rxbufs(card, sb); } 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?