📄 fore200e.c
字号:
/* $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ A FORE Systems 200E-series driver for ATM on Linux. Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). This driver simultaneously supports PCA-200E and SBA-200E adapters on i386, alpha (untested), powerpc, sparc and sparc64 architectures. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <linux/version.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/capability.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/bitops.h>#include <linux/atmdev.h>#include <linux/sonet.h>#include <linux/atm_suni.h>#include <asm/io.h>#include <asm/string.h>#include <asm/segment.h>#include <asm/page.h>#include <asm/irq.h>#include <asm/dma.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <linux/pci.h>#ifdef CONFIG_ATM_FORE200E_SBA#include <asm/idprom.h>#include <asm/sbus.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/pgtable.h>#endif#include <linux/module.h>#include "fore200e.h"#include "suni.h"#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */#define FORE200E_52BYTE_AAL0_SDU#endif#define FORE200E_VERSION "0.2d"#define FORE200E "fore200e: "#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ printk(FORE200E format, ##args); } while(0)#else#define DPRINTK(level, format, args...) while(0)#endif#define FORE200E_ALIGN(addr, alignment) \ ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr))#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type))#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ])#define FORE200E_NEXT_ENTRY(index, modulo) (index = ++(index) % (modulo))#define MSECS(ms) (((ms)*HZ/1000)+1)extern const struct atmdev_ops fore200e_ops;extern const struct fore200e_bus fore200e_bus[];static struct fore200e* fore200e_boards = NULL;#ifdef MODULEMODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen");MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION);MODULE_SUPPORTED_DEVICE("PCA-200E, SBA-200E");#endifstatic const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { { BUFFER_S1_NBR, BUFFER_L1_NBR }, { BUFFER_S2_NBR, BUFFER_L2_NBR }};static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, { BUFFER_S2_SIZE, BUFFER_L2_SIZE }};#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" };#endif#if 0 /* currently unused */static int fore200e_fore2atm_aal(enum fore200e_aal aal){ switch(aal) { case FORE200E_AAL0: return ATM_AAL0; case FORE200E_AAL34: return ATM_AAL34; case FORE200E_AAL5: return ATM_AAL5; } return -EINVAL;}#endifstatic enum fore200e_aalfore200e_atm2fore_aal(int aal){ switch(aal) { case ATM_AAL0: return FORE200E_AAL0; case ATM_AAL34: return FORE200E_AAL34; case ATM_AAL1: case ATM_AAL2: case ATM_AAL5: return FORE200E_AAL5; } return -EINVAL;}static char*fore200e_irq_itoa(int irq){#if defined(__sparc_v9__) return __irq_itoa(irq);#else static char str[8]; sprintf(str, "%d", irq); return str;#endif}static void*fore200e_kmalloc(int size, int flags){ void* chunk = kmalloc(size, flags); if (chunk) memset(chunk, 0x00, size); else printk(FORE200E "kmalloc() failed, requested size = %d, flags = 0x%x\n", size, flags); return chunk;}static voidfore200e_kfree(void* chunk){ kfree(chunk);}/* allocate and align a chunk of memory intended to hold the data behing exchanged between the driver and the adapter (using streaming DVMA) */static intfore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction){ unsigned long offset = 0; if (alignment <= sizeof(int)) alignment = 0; chunk->alloc_size = size + alignment; chunk->align_size = size; chunk->direction = direction; chunk->alloc_addr = fore200e_kmalloc(chunk->alloc_size, GFP_KERNEL | GFP_DMA); if (chunk->alloc_addr == NULL) return -ENOMEM; if (alignment > 0) offset = FORE200E_ALIGN(chunk->alloc_addr, alignment); chunk->align_addr = chunk->alloc_addr + offset; chunk->dma_addr = fore200e->bus->dma_map(fore200e, chunk->align_addr, chunk->align_size, direction); return 0;}/* free a chunk of memory */static voidfore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk){ fore200e->bus->dma_unmap(fore200e, chunk->dma_addr, chunk->dma_size, chunk->direction); fore200e_kfree(chunk->alloc_addr);}#if 0 /* currently unused */static intfore200e_checkup(struct fore200e* fore200e){ u32 hb1, hb2; hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); fore200e_spin(10); hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat); if (hb2 <= hb1) { printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n", fore200e->name, hb1, hb2); return -EIO; } printk(FORE200E "device %s heartbeat is ok\n", fore200e->name); return 0;}#endif static voidfore200e_spin(int msecs){ unsigned long timeout = jiffies + MSECS(msecs); while (jiffies < timeout);}static intfore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs){ unsigned long timeout = jiffies + MSECS(msecs); int ok; mb(); do { if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) break; } while (jiffies < timeout);#if 1 if (!ok) { printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n", *addr, val); }#endif return ok;}static intfore200e_io_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs){ unsigned long timeout = jiffies + MSECS(msecs); int ok; do { if ((ok = (fore200e->bus->read(addr) == val))) break; } while (jiffies < timeout);#if 1 if (!ok) { printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n", fore200e->bus->read(addr), val); }#endif return ok;}static voidfore200e_free_rx_buf(struct fore200e* fore200e){ int scheme, magn, nbr; struct buffer* buffer; for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { struct chunk* data = &buffer[ nbr ].data; if (data->alloc_addr != NULL) fore200e_chunk_free(fore200e, data); } } } }}static voidfore200e_uninit_bs_queue(struct fore200e* fore200e){ int scheme, magn; for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status; struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; if (status->alloc_addr) fore200e->bus->dma_chunk_free(fore200e, status); if (rbd_block->alloc_addr) fore200e->bus->dma_chunk_free(fore200e, rbd_block); } }}static intfore200e_reset(struct fore200e* fore200e, int diag){ int ok; fore200e->cp_monitor = (struct cp_monitor*)(fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET); fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); fore200e->bus->reset(fore200e); if (diag) { ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); if (ok == 0) { printk(FORE200E "device %s self-test failed\n", fore200e->name); return -ENODEV; } printk(FORE200E "device %s self-test passed\n", fore200e->name); fore200e->state = FORE200E_STATE_RESET; } return 0;}static voidfore200e_shutdown(struct fore200e* fore200e){ printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", fore200e->name, fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); if (fore200e->state > FORE200E_STATE_RESET) { /* first, reset the board to prevent further interrupts or data transfers */ fore200e_reset(fore200e, 0); } /* then, release all allocated resources */ switch(fore200e->state) { case FORE200E_STATE_COMPLETE: if (fore200e->stats) kfree(fore200e->stats); case FORE200E_STATE_IRQ: free_irq(fore200e->irq, fore200e->atm_dev); case FORE200E_STATE_ALLOC_BUF: fore200e_free_rx_buf(fore200e); case FORE200E_STATE_INIT_BSQ: fore200e_uninit_bs_queue(fore200e); case FORE200E_STATE_INIT_RXQ: fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.status); fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); case FORE200E_STATE_INIT_TXQ: fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.status); fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_txq.tpd); case FORE200E_STATE_INIT_CMDQ: fore200e->bus->dma_chunk_free(fore200e, &fore200e->host_cmdq.status); case FORE200E_STATE_INITIALIZE: /* nothing to do for that state */ case FORE200E_STATE_START_FW: /* nothing to do for that state */ case FORE200E_STATE_LOAD_FW: /* nothing to do for that state */ case FORE200E_STATE_RESET: /* nothing to do for that state */ case FORE200E_STATE_MAP: fore200e->bus->unmap(fore200e); case FORE200E_STATE_CONFIGURE: /* nothing to do for that state */ case FORE200E_STATE_REGISTER: /* XXX shouldn't we *start* by deregistering the device? */ atm_dev_deregister(fore200e->atm_dev); case FORE200E_STATE_BLANK: /* nothing to do for that state */ break; }}#ifdef CONFIG_ATM_FORE200E_PCAstatic u32 fore200e_pca_read(volatile u32* addr){ /* on big-endian hosts, the board is configured to convert the endianess of slave RAM accesses */ return le32_to_cpu(readl(addr));}static void fore200e_pca_write(u32 val, volatile u32* addr){ /* on big-endian hosts, the board is configured to convert the endianess of slave RAM accesses */ writel(cpu_to_le32(val), addr);}static u32fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction){ u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction); DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n", virt_addr, size, direction, dma_addr); return dma_addr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -