📄 fore200e.c
字号:
tmp.line_febe = fore200e_swap(fore200e->stats->oc3.line_febe_errors); tmp.path_febe = fore200e_swap(fore200e->stats->oc3.path_febe_errors); tmp.corr_hcs = fore200e_swap(fore200e->stats->oc3.corr_hcs_errors); tmp.uncorr_hcs = fore200e_swap(fore200e->stats->oc3.ucorr_hcs_errors); tmp.tx_cells = fore200e_swap(fore200e->stats->aal0.cells_transmitted) + fore200e_swap(fore200e->stats->aal34.cells_transmitted) + fore200e_swap(fore200e->stats->aal5.cells_transmitted); tmp.rx_cells = fore200e_swap(fore200e->stats->aal0.cells_received) + fore200e_swap(fore200e->stats->aal34.cells_received) + fore200e_swap(fore200e->stats->aal5.cells_received); if (arg) return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; return 0;}static intfore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void* arg){ struct fore200e* fore200e = FORE200E_DEV(dev); DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); switch (cmd) { case SONET_GETSTAT: return fore200e_fetch_stats(fore200e, (struct sonet_stats*)arg); case SONET_GETDIAG: return put_user(0, (int*)arg) ? -EFAULT : 0; case ATM_SETLOOP: return fore200e_setloop(fore200e, (int)(unsigned long)arg); case ATM_GETLOOP: return put_user(fore200e->loop_mode, (int*)arg) ? -EFAULT : 0; case ATM_QUERYLOOP: return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int*)arg) ? -EFAULT : 0; } return -ENOSYS; /* not implemented */}static intfore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags){ struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); struct fore200e* fore200e = FORE200E_DEV(vcc->dev); DPRINTK(2, "change_qos %d.%d.%d, " "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" "available_cell_rate = %u", vcc->itf, vcc->vpi, vcc->vci, fore200e_traffic_class[ qos->txtp.traffic_class ], qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, fore200e_traffic_class[ qos->rxtp.traffic_class ], qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, flags, fore200e->available_cell_rate); if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { down(&fore200e->rate_sf); if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { up(&fore200e->rate_sf); return -EAGAIN; } fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate -= qos->txtp.max_pcr; up(&fore200e->rate_sf); memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); /* update rate control parameters */ fore200e_rate_ctrl(qos, &fore200e_vcc->rate); set_bit(ATM_VF_HASQOS, &vcc->flags); return 0; } return -EINVAL;} static int __initfore200e_irq_request(struct fore200e* fore200e){ if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) { printk(FORE200E "unable to reserve IRQ %s for device %s\n", fore200e_irq_itoa(fore200e->irq), fore200e->name); return -EBUSY; } printk(FORE200E "IRQ %s reserved for device %s\n", fore200e_irq_itoa(fore200e->irq), fore200e->name); tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); fore200e->state = FORE200E_STATE_IRQ; return 0;}static int __initfore200e_get_esi(struct fore200e* fore200e){ struct prom_data* prom = fore200e_kmalloc(sizeof(struct prom_data), GFP_KERNEL | GFP_DMA); int ok, i; if (!prom) return -ENOMEM; ok = fore200e->bus->prom_read(fore200e, prom); if (ok < 0) { fore200e_kfree(prom); return -EBUSY; } printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", fore200e->name, (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ prom->serial_number & 0xFFFF, prom->mac_addr[ 2 ], prom->mac_addr[ 3 ], prom->mac_addr[ 4 ], prom->mac_addr[ 5 ], prom->mac_addr[ 6 ], prom->mac_addr[ 7 ]); for (i = 0; i < ESI_LEN; i++) { fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; } fore200e_kfree(prom); return 0;}static int __initfore200e_alloc_rx_buf(struct fore200e* fore200e){ int scheme, magn, nbr, size, i; struct host_bsq* bsq; 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 ]; nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; size = fore200e_rx_buf_size[ scheme ][ magn ]; DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); /* allocate the array of receive buffers */ buffer = bsq->buffer = fore200e_kmalloc(nbr * sizeof(struct buffer), GFP_KERNEL); if (buffer == NULL) return -ENOMEM; for (i = 0; i < nbr; i++) { buffer[ i ].scheme = scheme; buffer[ i ].magn = magn; /* allocate the receive buffer body */ if (fore200e_chunk_alloc(fore200e, &buffer[ i ].data, size, fore200e->bus->buffer_alignment, FORE200E_DMA_FROMDEVICE) < 0) { while (i > 0) fore200e_chunk_free(fore200e, &buffer[ --i ].data); fore200e_kfree(buffer); return -ENOMEM; } } /* set next free buffer index */ bsq->free = 0; } } fore200e->state = FORE200E_STATE_ALLOC_BUF; return 0;}static int __initfore200e_init_bs_queue(struct fore200e* fore200e){ int scheme, magn, i; struct host_bsq* bsq; struct cp_bsq_entry* cp_entry; for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); bsq = &fore200e->host_bsq[ scheme ][ magn ]; /* allocate and align the array of status words */ if (fore200e->bus->dma_chunk_alloc(fore200e, &bsq->status, sizeof(enum status), QUEUE_SIZE_BS, fore200e->bus->status_alignment) < 0) { return -ENOMEM; } /* allocate and align the array of receive buffer descriptors */ if (fore200e->bus->dma_chunk_alloc(fore200e, &bsq->rbd_block, sizeof(struct rbd_block), QUEUE_SIZE_BS, fore200e->bus->descr_alignment) < 0) { fore200e->bus->dma_chunk_free(fore200e, &bsq->status); return -ENOMEM; } /* get the base address of the cp resident buffer supply queue entries */ cp_entry = (struct cp_bsq_entry*)(fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ])); /* fill the host resident and cp resident buffer supply queue entries */ for (i = 0; i < QUEUE_SIZE_BS; i++) { bsq->host_entry[ i ].status = FORE200E_INDEX(bsq->status.align_addr, enum status, i); bsq->host_entry[ i ].rbd_block = FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); bsq->host_entry[ i ].rbd_block_dma = FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; *bsq->host_entry[ i ].status = STATUS_FREE; fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), &cp_entry[ i ].status_haddr); } } } fore200e->state = FORE200E_STATE_INIT_BSQ; return 0;}static int __initfore200e_init_rx_queue(struct fore200e* fore200e){ struct host_rxq* rxq = &fore200e->host_rxq; struct cp_rxq_entry* cp_entry; int i; DPRINTK(2, "receive queue is being initialized\n"); /* allocate and align the array of status words */ if (fore200e->bus->dma_chunk_alloc(fore200e, &rxq->status, sizeof(enum status), QUEUE_SIZE_RX, fore200e->bus->status_alignment) < 0) { return -ENOMEM; } /* allocate and align the array of receive PDU descriptors */ if (fore200e->bus->dma_chunk_alloc(fore200e, &rxq->rpd, sizeof(struct rpd), QUEUE_SIZE_RX, fore200e->bus->descr_alignment) < 0) { fore200e->bus->dma_chunk_free(fore200e, &rxq->status); return -ENOMEM; } /* get the base address of the cp resident rx queue entries */ cp_entry = (struct cp_rxq_entry*)(fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_rxq)); /* fill the host resident and cp resident rx entries */ for (i=0; i < QUEUE_SIZE_RX; i++) { rxq->host_entry[ i ].status = FORE200E_INDEX(rxq->status.align_addr, enum status, i); rxq->host_entry[ i ].rpd = FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i); rxq->host_entry[ i ].rpd_dma = FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i); rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; *rxq->host_entry[ i ].status = STATUS_FREE; fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i), &cp_entry[ i ].status_haddr); fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i), &cp_entry[ i ].rpd_haddr); } /* set the head entry of the queue */ rxq->head = 0; fore200e->state = FORE200E_STATE_INIT_RXQ; return 0;}static int __initfore200e_init_tx_queue(struct fore200e* fore200e){ struct host_txq* txq = &fore200e->host_txq; struct cp_txq_entry* cp_entry; int i; DPRINTK(2, "transmit queue is being initialized\n"); /* allocate and align the array of status words */ if (fore200e->bus->dma_chunk_alloc(fore200e, &txq->status, sizeof(enum status), QUEUE_SIZE_TX, fore200e->bus->status_alignment) < 0) { return -ENOMEM; } /* allocate and align the array of transmit PDU descriptors */ if (fore200e->bus->dma_chunk_alloc(fore200e, &txq->tpd, sizeof(struct tpd), QUEUE_SIZE_TX, fore200e->bus->descr_alignment) < 0) { fore200e->bus->dma_chunk_free(fore200e, &txq->status); return -ENOMEM; } /* get the base address of the cp resident tx queue entries */ cp_entry = (struct cp_txq_entry*)(fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_txq)); /* fill the host resident and cp resident tx entries */ for (i=0; i < QUEUE_SIZE_TX; i++) { txq->host_entry[ i ].status = FORE200E_INDEX(txq->status.align_addr, enum status, i); txq->host_entry[ i ].tpd = FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i); txq->host_entry[ i ].tpd_dma = FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i); txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; *txq->host_entry[ i ].status = STATUS_FREE; fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i), &cp_entry[ i ].status_haddr); /* although there is a one-to-one mapping of tx queue entries and tpds, we do not write here the DMA (physical) base address of each tpd into the related cp resident entry, because the cp relies on this write operation to detect that a new pdu has been submitted for tx */} /* set the head entry of the queue */ txq->head = 0; fore200e->state = FORE200E_STATE_INIT_TXQ; return 0;}static int __initfore200e_init_cmd_queue(struct fore200e* fore200e){ struct host_cmdq* cmdq = &fore200e->host_cmdq; struct cp_cmdq_entry* cp_entry; int i; DPRINTK(2, "command queue is being initialized\n"); /* allocate and align the array of status words */ if (fore200e->bus->dma_chunk_alloc(fore200e, &cmdq->status, sizeof(enum status), QUEUE_SIZE_CMD, fore200e->bus->status_alignment) < 0) { return -ENOMEM; } /* get the base address of the cp resident cmd queue entries */ cp_entry = (struct cp_cmdq_entry*)(fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq)); /* fill the host resident and cp resident cmd entries */ for (i=0; i < QUEUE_SIZE_CMD; i++) { cmdq->host_entry[ i ].status = FORE200E_INDEX(cmdq->status.align_addr, enum status, i); cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; *cmdq->host_entry[ i ].status = STATUS_FREE; fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i), &cp_entry[ i ].status_haddr); } /* set the head entry of the queue */ cmdq->head = 0; fore200e->state = FORE200E_STATE_INIT_CMDQ; return 0;}static void __initfore200e_param_bs_queue(struct fore200e* fore200e, enum buffer_scheme scheme, enum buffer_magn magn, int queue_length, int pool_size, int supply_blksize){ struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; /* dumb value; the firmware doesn't allow us to activate a VC while selecting a buffer scheme with zero-sized rbd pools */ if (pool_size == 0) pool_size = 64; fore200e->bus->write(queue_length, &bs_spec->queue_length); fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); fore200e->bus->write(pool_size, &bs_spec->pool_size); fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize);}static int __initfore200e_initialize(struct fore200e* fore200e){ struct cp_queues* cpq; int ok, scheme, magn; DPRINTK(2, "device %s being initialized\n", fore200e->name); init_MUTEX(&fore200e->rate_sf); cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); /* enable cp to host interrupts */ fore200e->bus->write(1, &cpq->imask); if (fore200e->bus->irq_enable) fore200e->bus->irq_enable(fore200e); fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) fore200e_param_bs_queue(fore200e, scheme, magn, QUEUE_SIZE_BS, fore200e_rx_buf_nbr[ scheme ][ magn ], RBD_BLK_SIZE); /* issue the initializ
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -