📄 nicstar.c
字号:
{ printk("nicstar%d: can't allocate %dth of %d small buffers.\n", i, j, NUM_SB); error = 15; ns_init_card_error(card, error); return error; } 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); } /* Test for strange behaviour which leads to crashes */ if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) { printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", i, j, bcount); error = 15; ns_init_card_error(card, error); return error; } /* Allocate iovec buffers */ skb_queue_head_init(&card->iovpool.queue); card->iovpool.count = 0; for (j = 0; j < NUM_IOVB; j++) { struct sk_buff *iovb; iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); if (iovb == NULL) { printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n", i, j, NUM_IOVB); error = 16; ns_init_card_error(card, error); return error; } skb_queue_tail(&card->iovpool.queue, iovb); card->iovpool.count++; } card->intcnt = 0; /* Configure NICStAR */ if (card->rct_size == 4096) ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; else /* (card->rct_size == 16384) */ ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; card->efbie = 1; /* Register device */ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL); if (card->atmdev == NULL) { printk("nicstar%d: can't register device.\n", i); error = 17; ns_init_card_error(card, error); return error; } if (ns_parse_mac(mac[i], card->atmdev->esi)) nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, card->atmdev->esi, 6); printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i, card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2], card->atmdev->esi[3], card->atmdev->esi[4], card->atmdev->esi[5]); card->atmdev->dev_data = card; card->atmdev->ci_range.vpi_bits = card->vpibits; 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); MOD_INC_USE_COUNT; /* Can't remove the nicstar driver or the suni driver would oops */ }#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 if (card->max_pcr == ATM_25_PCR) { idt77105_init(card->atmdev); /* Note that for the IDT77105 PHY we don't need the awful * module count hack that the SUNI needs because we can * stop the '105 when the nicstar module is cleaned up. */ }#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 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) { 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 void 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -