📄 idt77252.c
字号:
{ unsigned long flags; int res; spin_lock_irqsave(&card->tst_lock, flags); res = __clear_tst(card, vc); set_bit(TST_SWITCH_PENDING, &card->tst_state); if (!timer_pending(&card->tst_timer)) mod_timer(&card->tst_timer, jiffies + 1); spin_unlock_irqrestore(&card->tst_lock, flags); return res;}static intchange_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc){ unsigned long flags; int res; spin_lock_irqsave(&card->tst_lock, flags); __clear_tst(card, vc); res = __fill_tst(card, vc, n, opc); set_bit(TST_SWITCH_PENDING, &card->tst_state); if (!timer_pending(&card->tst_timer)) mod_timer(&card->tst_timer, jiffies + 1); spin_unlock_irqrestore(&card->tst_lock, flags); return res;}static intset_tct(struct idt77252_dev *card, struct vc_map *vc){ unsigned long tct; tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE); switch (vc->class) { case SCHED_CBR: OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", card->name, tct, vc->scq->scd); write_sram(card, tct + 0, TCT_CBR | vc->scq->scd); write_sram(card, tct + 1, 0); write_sram(card, tct + 2, 0); write_sram(card, tct + 3, 0); write_sram(card, tct + 4, 0); write_sram(card, tct + 5, 0); write_sram(card, tct + 6, 0); write_sram(card, tct + 7, 0); break; case SCHED_UBR: OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", card->name, tct, vc->scq->scd); write_sram(card, tct + 0, TCT_UBR | vc->scq->scd); write_sram(card, tct + 1, 0); write_sram(card, tct + 2, TCT_TSIF); write_sram(card, tct + 3, TCT_HALT | TCT_IDLE); write_sram(card, tct + 4, 0); write_sram(card, tct + 5, vc->init_er); write_sram(card, tct + 6, 0); write_sram(card, tct + 7, TCT_FLAG_UBR); break; case SCHED_VBR: case SCHED_ABR: default: return -ENOSYS; } return 0;}/*****************************************************************************//* *//* FBQ Handling *//* *//*****************************************************************************/static __inline__ intidt77252_fbq_level(struct idt77252_dev *card, int queue){ return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) & 0x0f;}static __inline__ intidt77252_fbq_full(struct idt77252_dev *card, int queue){ return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f;}static intpush_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue){ unsigned long flags; u32 handle; u32 addr; skb->data = skb->tail = skb->head; skb->len = 0; skb_reserve(skb, 16); switch (queue) { case 0: skb_put(skb, SAR_FB_SIZE_0); break; case 1: skb_put(skb, SAR_FB_SIZE_1); break; case 2: skb_put(skb, SAR_FB_SIZE_2); break; case 3: skb_put(skb, SAR_FB_SIZE_3); break; default: dev_kfree_skb(skb); return -1; } if (idt77252_fbq_full(card, queue)) return -1; memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32)); handle = IDT77252_PRV_POOL(skb); addr = IDT77252_PRV_PADDR(skb); spin_lock_irqsave(&card->cmd_lock, flags); writel(handle, card->fbq[queue]); writel(addr, card->fbq[queue]); spin_unlock_irqrestore(&card->cmd_lock, flags); return 0;}static voidadd_rx_skb(struct idt77252_dev *card, int queue, unsigned int size, unsigned int count){ struct sk_buff *skb; dma_addr_t paddr; u32 handle; while (count--) { skb = dev_alloc_skb(size); if (!skb) return; if (sb_pool_add(card, skb, queue)) { printk("%s: SB POOL full\n", __FUNCTION__); goto outfree; } paddr = pci_map_single(card->pcidev, skb->data, skb->end - skb->data, PCI_DMA_FROMDEVICE); IDT77252_PRV_PADDR(skb) = paddr; if (push_rx_skb(card, skb, queue)) { printk("%s: FB QUEUE full\n", __FUNCTION__); goto outunmap; } } return;outunmap: pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->end - skb->data, PCI_DMA_FROMDEVICE); handle = IDT77252_PRV_POOL(skb); card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;outfree: dev_kfree_skb(skb);}static voidrecycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb){ u32 handle = IDT77252_PRV_POOL(skb); int err; err = push_rx_skb(card, skb, POOL_QUEUE(handle)); if (err) { pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->end - skb->data, PCI_DMA_FROMDEVICE); sb_pool_remove(card, skb); dev_kfree_skb(skb); }}static voidflush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp){ rpp->len = 0; rpp->count = 0; rpp->first = NULL; rpp->last = &rpp->first;}static voidrecycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp){ struct sk_buff *skb, *next; int i; skb = rpp->first; for (i = 0; i < rpp->count; i++) { next = skb->next; skb->next = NULL; recycle_rx_skb(card, skb); skb = next; } flush_rx_pool(card, rpp);}/*****************************************************************************//* *//* ATM Interface *//* *//*****************************************************************************/static voididt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr){ write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value);}static unsigned charidt77252_phy_get(struct atm_dev *dev, unsigned long addr){ return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff));}static intidt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam){ struct atm_dev *dev = vcc->dev; struct idt77252_dev *card = dev->dev_data; struct vc_map *vc = vcc->dev_data; int err; if (vc == NULL) { printk("%s: NULL connection in send().\n", card->name); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } if (!test_bit(VCF_TX, &vc->flags)) { printk("%s: Trying to transmit on a non-tx VC.\n", card->name); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } switch (vcc->qos.aal) { case ATM_AAL0: case ATM_AAL1: case ATM_AAL5: break; default: printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } if (ATM_SKB(skb)->iovcnt != 0) { printk("%s: No scatter-gather yet.\n", card->name); atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); return -EINVAL; } ATM_SKB(skb)->vcc = vcc; err = queue_skb(card, vc, skb, oam); if (err) { atomic_inc(&vcc->stats->tx_err); dev_kfree_skb(skb); return err; } return 0;}intidt77252_send(struct atm_vcc *vcc, struct sk_buff *skb){ return idt77252_send_skb(vcc, skb, 0);}static intidt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags){ struct atm_dev *dev = vcc->dev; struct idt77252_dev *card = dev->dev_data; struct sk_buff *skb; skb = dev_alloc_skb(64); if (!skb) { printk("%s: Out of memory in send_oam().\n", card->name); atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->tx_inuse); ATM_SKB(skb)->iovcnt = 0; memcpy(skb_put(skb, 52), cell, 52); return idt77252_send_skb(vcc, skb, 1);}static __inline__ unsigned intidt77252_fls(unsigned int x){ int r = 1; if (x == 0) return 0; if (x & 0xffff0000) { x >>= 16; r += 16; } if (x & 0xff00) { x >>= 8; r += 8; } if (x & 0xf0) { x >>= 4; r += 4; } if (x & 0xc) { x >>= 2; r += 2; } if (x & 0x2) r += 1; return r;}static u16idt77252_int_to_atmfp(unsigned int rate){ u16 m, e; if (rate == 0) return 0; e = idt77252_fls(rate) - 1; if (e < 9) m = (rate - (1 << e)) << (9 - e); else if (e == 9) m = (rate - (1 << e)); else /* e > 9 */ m = (rate - (1 << e)) >> (e - 9); return 0x4000 | (e << 9) | m;}static u8idt77252_rate_logindex(struct idt77252_dev *card, int pcr){ u16 afp; afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr); if (pcr < 0) return rate_to_log[(afp >> 5) & 0x1ff]; return rate_to_log[((afp >> 5) + 1) & 0x1ff];}static voididt77252_est_timer(unsigned long data){ struct vc_map *vc = (struct vc_map *)data; struct idt77252_dev *card = vc->card; struct rate_estimator *est; unsigned long flags; u32 rate, cps; u64 ncells; u8 lacr; spin_lock_irqsave(&vc->lock, flags); est = vc->estimator; if (!est) goto out; ncells = est->cells; rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval); est->last_cells = ncells; est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log; est->cps = (est->avcps + 0x1f) >> 5; cps = est->cps; if (cps < (est->maxcps >> 4)) cps = est->maxcps >> 4; lacr = idt77252_rate_logindex(card, cps); if (lacr > vc->max_er) lacr = vc->max_er; if (lacr != vc->lacr) { vc->lacr = lacr; writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ); } est->timer.expires = jiffies + ((HZ / 4) << est->interval); add_timer(&est->timer);out: spin_unlock_irqrestore(&vc->lock, flags);}static struct rate_estimator *idt77252_init_est(struct vc_map *vc, int pcr){ struct rate_estimator *est; est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL); if (!est) return NULL; memset(est, 0, sizeof(*est)); est->maxcps = pcr < 0 ? -pcr : pcr; est->cps = est->maxcps; est->avcps = est->cps << 5; est->interval = 2; /* XXX: make this configurable */ est->ewma_log = 2; /* XXX: make this configurable */ est->timer.data = (unsigned long)vc; est->timer.function = idt77252_est_timer; init_timer(&est->timer); est->timer.expires = jiffies + ((HZ / 4) << est->interval); add_timer(&est->timer); return est;}static intidt77252_init_cbr(struct idt77252_dev *card, struct vc_map *vc, struct atm_vcc *vcc, struct atm_qos *qos){ int tst_free, tst_used, tst_entries; unsigned long tmpl, modl; int tcr, tcra; if ((qos->txtp.max_pcr == 0) && (qos->txtp.pcr == 0) && (qos->txtp.min_pcr == 0)) { printk("%s: trying to open a CBR VC with cell rate = 0\n", card->name); return -EINVAL; } tst_used = 0; tst_free = card->tst_free; if (test_bit(VCF_TX, &vc->flags)) tst_used = vc->ntste; tst_free += tst_used; tcr = atm_pcr_goal(&qos->txtp); tcra = tcr >= 0 ? tcr : -tcr; TXPRINTK("%s: CBR target cell rate = %d\n", card->name, tcra); tmpl = (unsigned long) tcra * ((unsigned long) card->tst_size - 2); modl = tmpl % (unsigned long)card->utopia_pcr; tst_entries = (int) (tmpl / card->utopia_pcr); if (tcr > 0) { if (modl > 0) tst_entries++; } else if (tcr == 0) { tst_entries = tst_free - SAR_TST_RESERVED; if (tst_entries <= 0) { printk("%s: no CBR bandwidth free.\n", card->name); return -ENOSR; } } if (tst_entries == 0) { printk("%s: selected CBR bandwidth < granularity.\n", card->name); return -EINVAL; } if (tst_entries > (tst_free - SAR_TST_RESERVED)) { printk("%s: not enough CBR bandwidth free.\n", card->name); return -ENOSR; } vc->ntste = tst_entries; card->tst_free = tst_free - tst_entries; if (test_bit(VCF_TX, &vc->flags)) { if (tst_used == tst_entries) return 0; OPRINTK("%s: modify %d -> %d entries in TST.\n", card->name, tst_used, tst_entries); change_tst(card, vc, tst_entries, TSTE_OPC_CBR); return 0; } OPRINTK("%s: setting %d entries in TST.\n", card->name, tst_entries); fill_tst(card, vc, tst_entries, TSTE_OPC_CBR); return 0;}static intidt77252_init_ubr(struct idt77252_dev *card, struct vc_map *vc, struct atm_vcc *vcc, struct atm_qos *qos){ unsigned long flags; int tcr; spin_lock_irqsave(&vc->lock, flags); if (vc->estimator) { del_timer(&vc->estimator->timer); kfree(vc->estimator); vc->estimator = NULL; } spin_unlock_irqrestore(&vc->lock, flags); tcr = atm_pcr_goal(&qos->txtp); if (tcr == 0) tcr = card->link_pcr; vc->estimator = idt77252_init_est(vc, tcr); vc->class = SCHED_UBR; vc->init_er = idt77252_rate_logindex(card, tcr); vc->lacr = vc->init_er; if (tcr < 0) vc->max_er = vc->init_er; else vc->max_er = 0xff; return 0;}static intidt77252_init_tx(struct idt77252_dev *card, struct vc_map *vc, struct atm_vcc *vcc, struct atm_qos *qos){ int error; if (test_bit(VCF_TX, &vc->flags)) return -EBUSY; switch (qos->txtp.traffic_class) { case ATM_CBR: vc->class = SCHED_CBR; break; case ATM_UBR: vc->class = SCHED_UBR; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -