📄 fore200e.c
字号:
static int __initfore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom){ struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev; int len; len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4); if (len < 0) return -EBUSY; len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4); if (len < 0) return -EBUSY; prom_getproperty(sbus_dev->prom_node, "serialnumber", (char*)&prom->serial_number, sizeof(prom->serial_number)); prom_getproperty(sbus_dev->prom_node, "promversion", (char*)&prom->hw_revision, sizeof(prom->hw_revision)); return 0;}static intfore200e_sba_proc_read(struct fore200e* fore200e, char *page){ struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; return sprintf(page, " SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);}#endif /* CONFIG_ATM_FORE200E_SBA */static voidfore200e_irq_tx(struct fore200e* fore200e){ struct host_txq_entry* entry; int i; entry = fore200e->host_txq.host_entry; for (i = 0; i < QUEUE_SIZE_TX; i++) { if (*entry->status & STATUS_COMPLETE) { DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); /* free copy of misaligned data */ if (entry->data) kfree(entry->data); /* remove DMA mapping */ fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); /* notify tx completion */ if (entry->vcc->pop) entry->vcc->pop(entry->vcc, entry->skb); else dev_kfree_skb_irq(entry->skb); /* check error condition */ if (*entry->status & STATUS_ERROR) atomic_inc(&entry->vcc->stats->tx_err); else atomic_inc(&entry->vcc->stats->tx); *entry->status = STATUS_FREE; fore200e->host_txq.txing--; } entry++; }}static voidfore200e_supply(struct fore200e* fore200e){ int scheme, magn, i; struct host_bsq* bsq; struct host_bsq_entry* entry; struct buffer* buffer; for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { bsq = &fore200e->host_bsq[ scheme ][ magn ]; if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", scheme, magn, bsq->count); entry = &bsq->host_entry[ bsq->head ]; FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); for (i = 0; i < RBD_BLK_SIZE; i++) { buffer = &bsq->buffer[ bsq->free ]; FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); } /* increase the number of supplied rx buffers */ bsq->count += RBD_BLK_SIZE; *entry->status = STATUS_PENDING; fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); } } }}static struct atm_vcc* fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd){ struct atm_vcc* vcc; for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) { if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) break; } return vcc;}static voidfore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd){ struct atm_vcc* vcc; struct sk_buff* skb; struct buffer* buffer; struct fore200e_vcc* fore200e_vcc; int i, pdu_len = 0;#ifdef FORE200E_52BYTE_AAL0_SDU u32 cell_header = 0;#endif vcc = fore200e_find_vcc(fore200e, rpd); if (vcc == NULL) { printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n", fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci); return; } fore200e_vcc = FORE200E_VCC(vcc);#ifdef FORE200E_52BYTE_AAL0_SDU if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | rpd->atm_header.clp; pdu_len = 4; }#endif /* compute total PDU length */ for (i = 0; i < rpd->nseg; i++) pdu_len += rpd->rsd[ i ].length; skb = alloc_skb(pdu_len, GFP_ATOMIC); if (skb == NULL) { printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len); atomic_inc(&vcc->stats->rx_drop); return; } skb->stamp = vcc->timestamp = xtime; #ifdef FORE200E_52BYTE_AAL0_SDU if (cell_header) { *((u32*)skb_put(skb, 4)) = cell_header; }#endif /* reassemble segments */ for (i = 0; i < rpd->nseg; i++) { /* rebuild rx buffer address from rsd handle */ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); /* ensure DMA synchronisation */ fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); } DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); if (pdu_len < fore200e_vcc->rx_min_pdu) fore200e_vcc->rx_min_pdu = pdu_len; if (pdu_len > fore200e_vcc->rx_max_pdu) fore200e_vcc->rx_max_pdu = pdu_len; /* push PDU */ if (atm_charge(vcc, skb->truesize) == 0) { DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", vcc->itf, vcc->vpi, vcc->vci); dev_kfree_skb_irq(skb); return; } vcc->push(vcc, skb); atomic_inc(&vcc->stats->rx);}static voidfore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd){ struct buffer* buffer; int i; for (i = 0; i < rpd->nseg; i++) { /* rebuild rx buffer address from rsd handle */ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); /* decrease the number of supplied rx buffers */ fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--; }}static voidfore200e_irq_rx(struct fore200e* fore200e){ struct host_rxq* rxq = &fore200e->host_rxq; struct host_rxq_entry* entry; for (;;) { entry = &rxq->host_entry[ rxq->head ]; /* no more received PDUs */ if ((*entry->status & STATUS_COMPLETE) == 0) break; FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); if ((*entry->status & STATUS_ERROR) == 0) { fore200e_push_rpd(fore200e, entry->rpd); } else { printk(FORE200E "damaged PDU on %d.%d.%d\n", fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); } fore200e_collect_rpd(fore200e, entry->rpd); fore200e_supply(fore200e); /* rewrite the rpd address to ack the received PDU */ fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); *entry->status = STATUS_FREE; }}static voidfore200e_interrupt(int irq, void* dev, struct pt_regs* regs){ struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); if (fore200e->bus->irq_check(fore200e) == 0) { DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); return; } DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); tasklet_schedule(&fore200e->tasklet); fore200e->bus->irq_ack(fore200e);}static voidfore200e_tasklet(unsigned long data){ struct fore200e* fore200e = (struct fore200e*) data; fore200e_irq_rx(fore200e); if (fore200e->host_txq.txing) fore200e_irq_tx(fore200e);}static intfore200e_select_scheme(struct atm_vcc* vcc){ int scheme;#if 1 /* fairly balance VCs over (identical) buffer schemes */ scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;#else /* bit 7 of VPI magically selects the second buffer scheme */ if (vcc->vpi & (1<<7)) { vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */ scheme = BUFFER_SCHEME_TWO; } else { scheme = BUFFER_SCHEME_ONE; }#endif DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n", vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second"); return scheme;}static int fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; struct activate_opcode activ_opcode; struct deactivate_opcode deactiv_opcode; struct vpvc vpvc; int ok; enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); if (activate) { FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; activ_opcode.aal = aal; activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; activ_opcode.pad = 0; } else { deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; deactiv_opcode.pad = 0; } vpvc.vci = vcc->vci; vpvc.vpi = vcc->vpi; *entry->status = STATUS_PENDING; if (activate) {#ifdef FORE200E_52BYTE_AAL0_SDU mtu = 48;#endif /* the MTU is unused by the cp, except in the case of AAL0 */ fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); } else { fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.deactivate_block.vpvc); fore200e->bus->write(*(u32*)&deactiv_opcode, (u32*)&entry->cp_entry->cmd.deactivate_block.opcode); } ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); *entry->status = STATUS_FREE; if (ok == 0) { printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); return -EIO; } DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, activate ? "open" : "clos", fore200e->name); return 0;}static intfore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci){ struct atm_vcc* walk; /* find a free VPI */ if (*vpi == ATM_VPI_ANY) { for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) { if ((walk->vci == *vci) && (walk->vpi == *vpi)) { (*vpi)++; walk = vcc->dev->vccs; } } } /* find a free VCI */ if (*vci == ATM_VCI_ANY) { for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) { if ((walk->vpi = *vpi) && (walk->vci == *vci)) { *vci = walk->vci + 1; walk = vcc->dev->vccs; } } } return 0;}#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */static voidfore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate){ if (qos->txtp.max_pcr < ATM_OC3_PCR) { /* compute the data cells to idle cells ratio from the PCR */ rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; } else { /* disable rate control */ rate->data_cells = rate->idle_cells = 0; }}static intfore200e_open(struct atm_vcc *vcc, short vpi, int vci){ struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e_vcc* fore200e_vcc; /* find a free VPI/VCI */ fore200e_walk_vccs(vcc, &vpi, &vci); vcc->vpi = vpi; vcc->vci = vci; /* ressource checking only? */ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; set_bit(ATM_VF_ADDR, &vcc->flags); vcc->itf = vcc->dev->number; DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -