📄 fore200e.c
字号:
if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { down(&fore200e->rate_sf); if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { up(&fore200e->rate_sf); return -EAGAIN; } /* reserving the pseudo-CBR bandwidth at this point grants us to reduce the length of the critical section protected by 'rate_sf'. in counterpart, we have to reset the available bandwidth if we later encounter an error */ fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); } fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); if (fore200e_vcc == NULL) { down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); return -ENOMEM; } FORE200E_VCC(vcc) = fore200e_vcc; if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { kfree(fore200e_vcc); down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); return -EBUSY; } /* compute rate control parameters */ if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); } fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; set_bit(ATM_VF_READY, &vcc->flags); return 0;}static voidfore200e_close(struct atm_vcc* vcc){ struct fore200e* fore200e = FORE200E_DEV(vcc->dev); DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); fore200e_activate_vcin(fore200e, 0, vcc, 0); kfree(FORE200E_VCC(vcc)); if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { down(&fore200e->rate_sf); fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; up(&fore200e->rate_sf); } clear_bit(ATM_VF_READY, &vcc->flags);}#if 0#define FORE200E_SYNC_SEND /* wait tx completion before returning */#endifstatic intfore200e_send(struct atm_vcc *vcc, struct sk_buff *skb){ struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); struct host_txq* txq = &fore200e->host_txq; struct host_txq_entry* entry; struct tpd* tpd; struct tpd_haddr tpd_haddr; //unsigned long flags; int retry = CONFIG_ATM_FORE200E_TX_RETRY; int tx_copy = 0; int tx_len = skb->len; u32* cell_header = NULL; unsigned char* skb_data; int skb_len;#ifdef FORE200E_52BYTE_AAL0_SDU if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { cell_header = (u32*) skb->data; skb_data = skb->data + 4; /* skip 4-byte cell header */ skb_len = tx_len = skb->len - 4; DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); } else #endif { skb_data = skb->data; skb_len = skb->len; } retry_here: tasklet_disable(&fore200e->tasklet); entry = &txq->host_entry[ txq->head ]; if (*entry->status != STATUS_FREE) { /* try to free completed tx queue entries */ fore200e_irq_tx(fore200e); if (*entry->status != STATUS_FREE) { tasklet_enable(&fore200e->tasklet); /* retry once again? */ if(--retry > 0) goto retry_here; atomic_inc(&vcc->stats->tx_err); printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", fore200e->name, fore200e->cp_queues->heartbeat); if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); return -EIO; } } tpd = entry->tpd; if (((unsigned long)skb_data) & 0x3) { DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); tx_copy = 1; tx_len = skb_len; } if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { /* this simply NUKES the PCA-200E board */ DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); tx_copy = 1; tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; } if (tx_copy) { entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA); if (entry->data == NULL) { tasklet_enable(&fore200e->tasklet); if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); return -ENOMEM; } memcpy(entry->data, skb_data, skb_len); if (skb_len < tx_len) memset(entry->data + skb_len, 0x00, tx_len - skb_len); tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE); } else { entry->data = NULL; tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE); } tpd->tsd[ 0 ].length = tx_len; FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); txq->txing++; tasklet_enable(&fore200e->tasklet); /* ensure DMA synchronisation */ fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), tpd->tsd[0].length, skb_len); if (skb_len < fore200e_vcc->tx_min_pdu) fore200e_vcc->tx_min_pdu = skb_len; if (skb_len > fore200e_vcc->tx_max_pdu) fore200e_vcc->tx_max_pdu = skb_len; entry->vcc = vcc; entry->skb = skb; /* set tx rate control information */ tpd->rate.data_cells = fore200e_vcc->rate.data_cells; tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; if (cell_header) { tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; } else { /* set the ATM header, common to all cells conveying the PDU */ tpd->atm_header.clp = 0; tpd->atm_header.plt = 0; tpd->atm_header.vci = vcc->vci; tpd->atm_header.vpi = vcc->vpi; tpd->atm_header.gfc = 0; } tpd->spec.length = tx_len; tpd->spec.nseg = 1; tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal);#ifdef FORE200E_SYNC_SEND tpd->spec.intr = 0;#else tpd->spec.intr = 1;#endif tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ tpd_haddr.pad = 0; tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr);#ifdef FORE200E_SYNC_SEND { int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10); fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); /* free tmp copy of misaligned data */ if (entry->data) kfree(entry->data); /* notify tx completion */ if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb(skb); if (ok == 0) { printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci); atomic_inc(&entry->vcc->stats->tx_err); return -EIO; } atomic_inc(&entry->vcc->stats->tx); DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci); }#endif return 0;}static intfore200e_getstats(struct fore200e* fore200e){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; struct stats_opcode opcode; int ok; u32 stats_dma_addr; if (fore200e->stats == NULL) { fore200e->stats = fore200e_kmalloc(sizeof(struct stats), GFP_KERNEL | GFP_DMA); if (fore200e->stats == NULL) return -ENOMEM; } stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); opcode.opcode = OPCODE_GET_STATS; opcode.pad = 0; fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr); *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.stats_block.opcode); ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); *entry->status = STATUS_FREE; fore200e->bus->dma_unmap(fore200e, stats_dma_addr, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); return -EIO; } return 0;}static intfore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen){ // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); return -EINVAL;}static intfore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen){ // struct fore200e* fore200e = FORE200E_DEV(vcc->dev); DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); return -EINVAL;}#if 0 /* currently unused */static intfore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; struct oc3_opcode opcode; int ok; u32 oc3_regs_dma_addr; oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); opcode.opcode = OPCODE_GET_OC3; opcode.reg = 0; opcode.value = 0; opcode.mask = 0; fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr); *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); *entry->status = STATUS_FREE; fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), FORE200E_DMA_FROMDEVICE); if (ok == 0) { printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); return -EIO; } return 0;}#endifstatic intfore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; struct oc3_opcode opcode; int ok; FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); opcode.opcode = OPCODE_SET_OC3; opcode.reg = reg; opcode.value = value; opcode.mask = mask; fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); *entry->status = STATUS_PENDING; fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); *entry->status = STATUS_FREE; if (ok == 0) { printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); return -EIO; } return 0;}static intfore200e_setloop(struct fore200e* fore200e, int loop_mode){ u32 mct_value, mct_mask; int error; if (!capable(CAP_NET_ADMIN)) return -EPERM; switch (loop_mode) { case ATM_LM_NONE: mct_value = 0; mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; break; case ATM_LM_LOC_PHY: mct_value = mct_mask = SUNI_MCT_DLE; break; case ATM_LM_RMT_PHY: mct_value = mct_mask = SUNI_MCT_LLE; break; default: return -EINVAL; } error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); if ( error == 0) fore200e->loop_mode = loop_mode; return error;}static inline unsigned intfore200e_swap(unsigned int in){#if defined(__LITTLE_ENDIAN) return swab32(in);#else return in;#endif}static intfore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats* arg){ struct sonet_stats tmp; if (fore200e_getstats(fore200e) < 0) return -EIO; tmp.section_bip = fore200e_swap(fore200e->stats->oc3.section_bip8_errors); tmp.line_bip = fore200e_swap(fore200e->stats->oc3.line_bip24_errors); tmp.path_bip = fore200e_swap(fore200e->stats->oc3.path_bip8_errors);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -