📄 idt77252.c
字号:
printk("%s: Connection %d:\n", card->name, vc->index); dump_tct(card, vc->index); }}#endif/*****************************************************************************//* *//* SCQ Handling *//* *//*****************************************************************************/static intsb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue){ struct sb_pool *pool = &card->sbpool[queue]; int index; index = pool->index; while (pool->skb[index]) { index = (index + 1) & FBQ_MASK; if (index == pool->index) return -ENOBUFS; } pool->skb[index] = skb; IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index); pool->index = (index + 1) & FBQ_MASK; return 0;}static voidsb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb){ unsigned int queue, index; u32 handle; handle = IDT77252_PRV_POOL(skb); queue = POOL_QUEUE(handle); if (queue > 3) return; index = POOL_INDEX(handle); if (index > FBQ_SIZE - 1) return; card->sbpool[queue].skb[index] = NULL;}static struct sk_buff *sb_pool_skb(struct idt77252_dev *card, u32 handle){ unsigned int queue, index; queue = POOL_QUEUE(handle); if (queue > 3) return NULL; index = POOL_INDEX(handle); if (index > FBQ_SIZE - 1) return NULL; return card->sbpool[queue].skb[index];}static struct scq_info *alloc_scq(struct idt77252_dev *card, int class){ struct scq_info *scq; scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL); if (!scq) return NULL; memset(scq, 0, sizeof(struct scq_info)); scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE, &scq->paddr); if (scq->base == NULL) { kfree(scq); return NULL; } memset(scq->base, 0, SCQ_SIZE); scq->next = scq->base; scq->last = scq->base + (SCQ_ENTRIES - 1); atomic_set(&scq->used, 0); spin_lock_init(&scq->lock); spin_lock_init(&scq->skblock); skb_queue_head_init(&scq->transmit); skb_queue_head_init(&scq->pending); TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08x\n", scq->base, scq->next, scq->last, scq->paddr); return scq;}static voidfree_scq(struct idt77252_dev *card, struct scq_info *scq){ struct sk_buff *skb; struct atm_vcc *vcc; pci_free_consistent(card->pcidev, SCQ_SIZE, scq->base, scq->paddr); while ((skb = skb_dequeue(&scq->transmit))) { pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->len, PCI_DMA_TODEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); } while ((skb = skb_dequeue(&scq->pending))) { pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->len, PCI_DMA_TODEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); } kfree(scq);}static intpush_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb){ struct scq_info *scq = vc->scq; unsigned long flags; struct scqe *tbd; int entries; TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next); atomic_inc(&scq->used); entries = atomic_read(&scq->used); if (entries > (SCQ_ENTRIES - 1)) { atomic_dec(&scq->used); goto out; } skb_queue_tail(&scq->transmit, skb); spin_lock_irqsave(&vc->lock, flags); if (vc->estimator) { struct atm_vcc *vcc = vc->tx_vcc; vc->estimator->cells += (skb->len + 47) / 48; if (atomic_read(&vcc->tx_inuse) > (vcc->sk->sndbuf >> 1)) { u32 cps = vc->estimator->maxcps; vc->estimator->cps = cps; vc->estimator->avcps = cps << 5; if (vc->lacr < vc->init_er) { vc->lacr = vc->init_er; writel(TCMDQ_LACR | (vc->lacr << 16) | vc->index, SAR_REG_TCMDQ); } } } spin_unlock_irqrestore(&vc->lock, flags); tbd = &IDT77252_PRV_TBD(skb); spin_lock_irqsave(&scq->lock, flags); scq->next->word_1 = cpu_to_le32(tbd->word_1 | SAR_TBD_TSIF | SAR_TBD_GTSI); scq->next->word_2 = cpu_to_le32(tbd->word_2); scq->next->word_3 = cpu_to_le32(tbd->word_3); scq->next->word_4 = cpu_to_le32(tbd->word_4); if (scq->next == scq->last) scq->next = scq->base; else scq->next++; write_sram(card, scq->scd, scq->paddr + (u32)((unsigned long)scq->next - (unsigned long)scq->base)); spin_unlock_irqrestore(&scq->lock, flags); scq->trans_start = jiffies; if (test_and_clear_bit(VCF_IDLE, &vc->flags)) { writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index, SAR_REG_TCMDQ); } TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used)); XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n", card->name, atomic_read(&scq->used), read_sram(card, scq->scd + 1), scq->next); return 0;out: if (jiffies - scq->trans_start > HZ) { printk("%s: Error pushing TBD for %d.%d\n", card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci);#ifdef CONFIG_ATM_IDT77252_DEBUG idt77252_tx_dump(card);#endif scq->trans_start = jiffies; } return -ENOBUFS;}static voiddrain_scq(struct idt77252_dev *card, struct vc_map *vc){ struct scq_info *scq = vc->scq; struct sk_buff *skb; struct atm_vcc *vcc; TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n", card->name, atomic_read(&scq->used), scq->next); skb = skb_dequeue(&scq->transmit); if (skb) { TXPRINTK("%s: freeing skb at %p.\n", card->name, skb); pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->len, PCI_DMA_TODEVICE); vcc = ATM_SKB(skb)->vcc; if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); atomic_inc(&vcc->stats->tx); } atomic_dec(&scq->used); spin_lock(&scq->skblock); while ((skb = skb_dequeue(&scq->pending))) { if (push_on_scq(card, vc, skb)) { skb_queue_head(&vc->scq->pending, skb); break; } } spin_unlock(&scq->skblock);}static intqueue_skb(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb, int oam){ struct atm_vcc *vcc; struct scqe *tbd; unsigned long flags; int error; int aal; if (skb->len == 0) { printk("%s: invalid skb->len (%d)\n", card->name, skb->len); return -EINVAL; } TXPRINTK("%s: Sending %d bytes of data.\n", card->name, skb->len); tbd = &IDT77252_PRV_TBD(skb); vcc = ATM_SKB(skb)->vcc; IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE); error = -EINVAL; if (oam) { if (skb->len != 52) goto errout; tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU; tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; tbd->word_3 = 0x00000000; tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) | (skb->data[2] << 8) | (skb->data[3] << 0); if (test_bit(VCF_RSV, &vc->flags)) vc = card->vcs[0]; goto done; } if (test_bit(VCF_RSV, &vc->flags)) { printk("%s: Trying to transmit on reserved VC\n", card->name); goto errout; } aal = vcc->qos.aal; switch (aal) { case ATM_AAL0: case ATM_AAL34: if (skb->len > 52) goto errout; if (aal == ATM_AAL0) tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 | ATM_CELL_PAYLOAD; else tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 | ATM_CELL_PAYLOAD; tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; tbd->word_3 = 0x00000000; tbd->word_4 = (skb->data[0] << 24) | (skb->data[1] << 16) | (skb->data[2] << 8) | (skb->data[3] << 0); break; case ATM_AAL5: tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len; tbd->word_2 = IDT77252_PRV_PADDR(skb); tbd->word_3 = skb->len; tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) | (vcc->vci << SAR_TBD_VCI_SHIFT); break; case ATM_AAL1: case ATM_AAL2: default: printk("%s: Traffic type not supported.\n", card->name); error = -EPROTONOSUPPORT; goto errout; }done: spin_lock_irqsave(&vc->scq->skblock, flags); skb_queue_tail(&vc->scq->pending, skb); while ((skb = skb_dequeue(&vc->scq->pending))) { if (push_on_scq(card, vc, skb)) { skb_queue_head(&vc->scq->pending, skb); break; } } spin_unlock_irqrestore(&vc->scq->skblock, flags); return 0;errout: pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->len, PCI_DMA_TODEVICE); return error;}static unsigned longget_free_scd(struct idt77252_dev *card, struct vc_map *vc){ int i; for (i = 0; i < card->scd_size; i++) { if (!card->scd2vc[i]) { card->scd2vc[i] = vc; vc->scd_index = i; return card->scd_base + i * SAR_SRAM_SCD_SIZE; } } return 0;}static voidfill_scd(struct idt77252_dev *card, struct scq_info *scq, int class){ write_sram(card, scq->scd, scq->paddr); write_sram(card, scq->scd + 1, 0x00000000); write_sram(card, scq->scd + 2, 0xffffffff); write_sram(card, scq->scd + 3, 0x00000000);}static voidclear_scd(struct idt77252_dev *card, struct scq_info *scq, int class){ return;}/*****************************************************************************//* *//* RSQ Handling *//* *//*****************************************************************************/static intinit_rsq(struct idt77252_dev *card){ struct rsq_entry *rsqe; card->rsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE, &card->rsq.paddr); if (card->rsq.base == NULL) { printk("%s: can't allocate RSQ.\n", card->name); return -1; } memset(card->rsq.base, 0, RSQSIZE); card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1; card->rsq.next = card->rsq.last; for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++) rsqe->word_4 = 0; writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base, SAR_REG_RSQH); writel(card->rsq.paddr, SAR_REG_RSQB); IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name, (unsigned long) card->rsq.base, readl(SAR_REG_RSQB)); IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n", card->name, readl(SAR_REG_RSQH), readl(SAR_REG_RSQB), readl(SAR_REG_RSQT)); return 0;}static voiddeinit_rsq(struct idt77252_dev *card){ pci_free_consistent(card->pcidev, RSQSIZE, card->rsq.base, card->rsq.paddr);}static voiddequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe){ struct atm_vcc *vcc; struct sk_buff *skb; struct rx_pool *rpp; struct vc_map *vc; u32 header, vpi, vci; u32 stat; int i; stat = le32_to_cpu(rsqe->word_4); if (stat & SAR_RSQE_IDLE) { RXPRINTK("%s: message about inactive connection.\n", card->name); return; } skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2)); if (skb == NULL) { printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n", card->name, __FUNCTION__, le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2), le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4)); return; } header = le32_to_cpu(rsqe->word_1); vpi = (header >> 16) & 0x00ff; vci = (header >> 0) & 0xffff; RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n", card->name, vpi, vci, skb, skb->data); if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) { printk("%s: SDU received for out-of-range vc %u.%u\n", card->name, vpi, vci); recycle_rx_skb(card, skb); return; } vc = card->vcs[VPCI2VC(card, vpi, vci)]; if (!vc || !test_bit(VCF_RX, &vc->flags)) { printk("%s: SDU received on non RX vc %u.%u\n", card->name, vpi, vci); recycle_rx_skb(card, skb); return; } vcc = vc->rx_vcc; pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb), skb->end - skb->data, PCI_DMA_FROMDEVICE); if ((vcc->qos.aal == ATM_AAL0) || (vcc->qos.aal == ATM_AAL34)) { struct sk_buff *sb; unsigned char *cell; u32 aal0; cell = skb->data; for (i = (stat & SAR_RSQE_CELLCNT); i; i--) { if ((sb = dev_alloc_skb(64)) == NULL) { printk("%s: Can't allocate buffers for aal0.\n", card->name); atomic_add(i, &vcc->stats->rx_drop); break; } if (!atm_charge(vcc, sb->truesize)) { RXPRINTK("%s: atm_charge() dropped aal0 packets.\n", card->name); atomic_add(i - 1, &vcc->stats->rx_drop); dev_kfree_skb(sb); break; } aal0 = (vpi << ATM_HDR_VPI_SHIFT) | (vci << ATM_HDR_VCI_SHIFT); aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0; aal0 |= (stat & SAR_RSQE_CLP) ? 0x00000001 : 0; *((u32 *) sb->data) = aal0; skb_put(sb, sizeof(u32)); memcpy(skb_put(sb, ATM_CELL_PAYLOAD), cell, ATM_CELL_PAYLOAD); ATM_SKB(sb)->vcc = vcc; sb->stamp = xtime; vcc->push(vcc, sb); atomic_inc(&vcc->stats->rx); cell += ATM_CELL_PAYLOAD; } recycle_rx_skb(card, skb); return; } if (vcc->qos.aal != ATM_AAL5) { printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n", card->name, vcc->qos.aal); recycle_rx_skb(card, skb); return; } skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD; rpp = &vc->rcv.rx_pool; rpp->len += skb->len; if (!rpp->count++) rpp->first = skb; *rpp->last = skb; rpp->last = &skb->next; if (stat & SAR_RSQE_EPDU) { unsigned char *l1l2; unsigned int len; l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6); len = (l1l2[0] << 8) | l1l2[1]; len = len ? len : 0x10000; RXPRINTK("%s: PDU has %d bytes.\n", card->name, len); if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) { RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. "
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -