lanai.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,038 行 · 第 1/5 页
C
2,038 行
/* lanai.c -- Copyright 1999-2003 by Mitchell Blank Jr <mitch@sfgoth.com> * * 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 driver supports ATM cards based on the Efficient "Lanai" * chipset such as the Speedstream 3010 and the ENI-25p. The * Speedstream 3060 is currently not supported since we don't * have the code to drive the on-board Alcatel DSL chipset (yet). * * Thanks to Efficient for supporting this project with hardware, * documentation, and by answering my questions. * * Things not working yet: * * o We don't support the Speedstream 3060 yet - this card has * an on-board DSL modem chip by Alcatel and the driver will * need some extra code added to handle it * * o Note that due to limitations of the Lanai only one VCC can be * in CBR at once * * o We don't currently parse the EEPROM at all. The code is all * there as per the spec, but it doesn't actually work. I think * there may be some issues with the docs. Anyway, do NOT * enable it yet - bugs in that code may actually damage your * hardware! Because of this you should hardware an ESI before * trying to use this in a LANE or MPOA environment. * * o AAL0 is stubbed in but the actual rx/tx path isn't written yet: * vcc_tx_aal0() needs to send or queue a SKB * vcc_tx_unqueue_aal0() needs to attempt to send queued SKBs * vcc_rx_aal0() needs to handle AAL0 interrupts * This isn't too much work - I just wanted to get other things * done first. * * o lanai_change_qos() isn't written yet * * o There aren't any ioctl's yet -- I'd like to eventually support * setting loopback and LED modes that way. (see lanai_ioctl) * * o If the segmentation engine or DMA gets shut down we should restart * card as per section 17.0i. (see lanai_reset) * * o setsockopt(SO_CIRANGE) isn't done (although despite what the * API says it isn't exactly commonly implemented) *//* Version history: * v.1.00 -- 26-JUL-2003 -- PCI/DMA updates * v.0.02 -- 11-JAN-2000 -- Endian fixes * v.0.01 -- 30-NOV-1999 -- Initial release */#include <linux/module.h>#include <linux/mm.h>#include <linux/atmdev.h>#include <asm/io.h>#include <asm/byteorder.h>#include <linux/spinlock.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/interrupt.h>/* -------------------- TUNABLE PARAMATERS: *//* * Maximum number of VCIs per card. Setting it lower could theoretically * save some memory, but since we allocate our vcc list with get_free_pages, * it's not really likely for most architectures */#define NUM_VCI (1024)/* * Enable extra debugging */#define DEBUG/* * Debug _all_ register operations with card, except the memory test. * Also disables the timed poll to prevent extra chattiness. This * isn't for normal use */#undef DEBUG_RW/* * The programming guide specifies a full test of the on-board SRAM * at initialization time. Undefine to remove this */#define FULL_MEMORY_TEST/* * This is the number of (4 byte) service entries that we will * try to allocate at startup. Note that we will end up with * one PAGE_SIZE's worth regardless of what this is set to */#define SERVICE_ENTRIES (1024)/* TODO: make above a module load-time option *//* * We normally read the onboard EEPROM in order to discover our MAC * address. Undefine to _not_ do this *//* #define READ_EEPROM */ /* ***DONT ENABLE YET*** *//* TODO: make above a module load-time option (also) *//* * Depth of TX fifo (in 128 byte units; range 2-31) * Smaller numbers are better for network latency * Larger numbers are better for PCI latency * I'm really sure where the best tradeoff is, but the BSD driver uses * 7 and it seems to work ok. */#define TX_FIFO_DEPTH (7)/* TODO: make above a module load-time option *//* * How often (in jiffies) we will try to unstick stuck connections - * shouldn't need to happen much */#define LANAI_POLL_PERIOD (10*HZ)/* TODO: make above a module load-time option *//* * When allocating an AAL5 receiving buffer, try to make it at least * large enough to hold this many max_sdu sized PDUs */#define AAL5_RX_MULTIPLIER (3)/* TODO: make above a module load-time option *//* * Same for transmitting buffer */#define AAL5_TX_MULTIPLIER (3)/* TODO: make above a module load-time option *//* * When allocating an AAL0 transmiting buffer, how many cells should fit. * Remember we'll end up with a PAGE_SIZE of them anyway, so this isn't * really critical */#define AAL0_TX_MULTIPLIER (40)/* TODO: make above a module load-time option *//* * How large should we make the AAL0 receiving buffer. Remember that this * is shared between all AAL0 VC's */#define AAL0_RX_BUFFER_SIZE (PAGE_SIZE)/* TODO: make above a module load-time option *//* * Should we use Lanai's "powerdown" feature when no vcc's are bound? *//* #define USE_POWERDOWN *//* TODO: make above a module load-time option (also) *//* -------------------- DEBUGGING AIDS: */#define DEV_LABEL "lanai"#ifdef DEBUG#define DPRINTK(format, args...) \ printk(KERN_DEBUG DEV_LABEL ": " format, ##args)#define APRINTK(truth, format, args...) \ do { \ if (unlikely(!(truth))) \ printk(KERN_ERR DEV_LABEL ": " format, ##args); \ } while (0)#else /* !DEBUG */#define DPRINTK(format, args...)#define APRINTK(truth, format, args...)#endif /* DEBUG */#ifdef DEBUG_RW#define RWDEBUG(format, args...) \ printk(KERN_DEBUG DEV_LABEL ": " format, ##args)#else /* !DEBUG_RW */#define RWDEBUG(format, args...)#endif/* -------------------- DATA DEFINITIONS: */#define LANAI_MAPPING_SIZE (0x40000)#define LANAI_EEPROM_SIZE (128)typedef int vci_t;typedef void __iomem *bus_addr_t;/* DMA buffer in host memory for TX, RX, or service list. */struct lanai_buffer { u32 *start; /* From get_free_pages */ u32 *end; /* One past last byte */ u32 *ptr; /* Pointer to current host location */ dma_addr_t dmaaddr;};struct lanai_vcc_stats { unsigned rx_nomem; union { struct { unsigned rx_badlen; unsigned service_trash; unsigned service_stream; unsigned service_rxcrc; } aal5; struct { } aal0; } x;};struct lanai_dev; /* Forward declaration *//* * This is the card-specific per-vcc data. Note that unlike some other * drivers there is NOT a 1-to-1 correspondance between these and * atm_vcc's - each one of these represents an actual 2-way vcc, but * an atm_vcc can be 1-way and share with a 1-way vcc in the other * direction. To make it weirder, there can even be 0-way vccs * bound to us, waiting to do a change_qos */struct lanai_vcc { bus_addr_t vbase; /* Base of VCC's registers */ struct lanai_vcc_stats stats; int nref; /* # of atm_vcc's who reference us */ vci_t vci; struct { struct lanai_buffer buf; struct atm_vcc *atmvcc; /* atm_vcc who is receiver */ } rx; struct { struct lanai_buffer buf; struct atm_vcc *atmvcc; /* atm_vcc who is transmitter */ int endptr; /* last endptr from service entry */ struct sk_buff_head backlog; void (*unqueue)(struct lanai_dev *, struct lanai_vcc *, int); } tx;};enum lanai_type { lanai2 = PCI_VENDOR_ID_EF_ATM_LANAI2, lanaihb = PCI_VENDOR_ID_EF_ATM_LANAIHB};struct lanai_dev_stats { unsigned ovfl_trash; /* # of cells dropped - buffer overflow */ unsigned vci_trash; /* # of cells dropped - closed vci */ unsigned hec_err; /* # of cells dropped - bad HEC */ unsigned atm_ovfl; /* # of cells dropped - rx fifo overflow */ unsigned pcierr_parity_detect; unsigned pcierr_serr_set; unsigned pcierr_master_abort; unsigned pcierr_m_target_abort; unsigned pcierr_s_target_abort; unsigned pcierr_master_parity; unsigned service_notx; unsigned service_norx; unsigned service_rxnotaal5; unsigned dma_reenable; unsigned card_reset;};struct lanai_dev { bus_addr_t base; struct lanai_dev_stats stats; struct lanai_buffer service; struct lanai_vcc **vccs;#ifdef USE_POWERDOWN int nbound; /* number of bound vccs */#endif enum lanai_type type; vci_t num_vci; /* Currently just NUM_VCI */ u8 eeprom[LANAI_EEPROM_SIZE]; u32 serialno, magicno; struct pci_dev *pci; DECLARE_BITMAP(backlog_vccs, NUM_VCI); /* VCCs with tx backlog */ DECLARE_BITMAP(transmit_ready, NUM_VCI); /* VCCs with transmit space */ struct timer_list timer; int naal0; struct lanai_buffer aal0buf; /* AAL0 RX buffers */ u32 conf1, conf2; /* CONFIG[12] registers */ u32 status; /* STATUS register */ spinlock_t endtxlock; spinlock_t servicelock; struct atm_vcc *cbrvcc; int number; int board_rev; u8 pci_revision;/* TODO - look at race conditions with maintence of conf1/conf2 *//* TODO - transmit locking: should we use _irq not _irqsave? *//* TODO - organize above in some rational fashion (see <asm/cache.h>) */};/* * Each device has two bitmaps for each VCC (baclog_vccs and transmit_ready) * This function iterates one of these, calling a given function for each * vci with their bit set */static void vci_bitfield_iterate(struct lanai_dev *lanai, /*const*/ unsigned long *lp, void (*func)(struct lanai_dev *,vci_t vci)){ vci_t vci = find_first_bit(lp, NUM_VCI); while (vci < NUM_VCI) { func(lanai, vci); vci = find_next_bit(lp, NUM_VCI, vci + 1); }}/* -------------------- BUFFER UTILITIES: *//* * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes - * usually any page allocation will do. Just to be safe in case * PAGE_SIZE is insanely tiny, though... */#define LANAI_PAGE_SIZE ((PAGE_SIZE >= 1024) ? PAGE_SIZE : 1024)/* * Allocate a buffer in host RAM for service list, RX, or TX * Returns buf->start==NULL if no memory * Note that the size will be rounded up 2^n bytes, and * if we can't allocate that we'll settle for something smaller * until minbytes */static void lanai_buf_allocate(struct lanai_buffer *buf, size_t bytes, size_t minbytes, struct pci_dev *pci){ int size; if (bytes > (128 * 1024)) /* max lanai buffer size */ bytes = 128 * 1024; for (size = LANAI_PAGE_SIZE; size < bytes; size *= 2) ; if (minbytes < LANAI_PAGE_SIZE) minbytes = LANAI_PAGE_SIZE; do { /* * Technically we could use non-consistent mappings for * everything, but the way the lanai uses DMA memory would * make that a terrific pain. This is much simpler. */ buf->start = pci_alloc_consistent(pci, size, &buf->dmaaddr); if (buf->start != NULL) { /* Success */ /* Lanai requires 256-byte alignment of DMA bufs */ APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0, "bad dmaaddr: 0x%lx\n", (unsigned long) buf->dmaaddr); buf->ptr = buf->start; buf->end = (u32 *) (&((unsigned char *) buf->start)[size]); memset(buf->start, 0, size); break; } size /= 2; } while (size >= minbytes);}/* size of buffer in bytes */static inline size_t lanai_buf_size(const struct lanai_buffer *buf){ return ((unsigned long) buf->end) - ((unsigned long) buf->start);}static void lanai_buf_deallocate(struct lanai_buffer *buf, struct pci_dev *pci){ if (buf->start != NULL) { pci_free_consistent(pci, lanai_buf_size(buf), buf->start, buf->dmaaddr); buf->start = buf->end = buf->ptr = NULL; }}/* size of buffer as "card order" (0=1k .. 7=128k) */static int lanai_buf_size_cardorder(const struct lanai_buffer *buf){ int order = get_order(lanai_buf_size(buf)) + (PAGE_SHIFT - 10); /* This can only happen if PAGE_SIZE is gigantic, but just in case */ if (order > 7) order = 7; return order;}/* -------------------- PORT I/O UTILITIES: *//* Registers (and their bit-fields) */enum lanai_register { Reset_Reg = 0x00, /* Reset; read for chip type; bits: */#define RESET_GET_BOARD_REV(x) (((x)>> 0)&0x03) /* Board revision */#define RESET_GET_BOARD_ID(x) (((x)>> 2)&0x03) /* Board ID */#define BOARD_ID_LANAI256 (0) /* 25.6M adapter card */ Endian_Reg = 0x04, /* Endian setting */ IntStatus_Reg = 0x08, /* Interrupt status */ IntStatusMasked_Reg = 0x0C, /* Interrupt status (masked) */ IntAck_Reg = 0x10, /* Interrupt acknowledge */ IntAckMasked_Reg = 0x14, /* Interrupt acknowledge (masked) */ IntStatusSet_Reg = 0x18, /* Get status + enable/disable */ IntStatusSetMasked_Reg = 0x1C, /* Get status + en/di (masked) */ IntControlEna_Reg = 0x20, /* Interrupt control enable */ IntControlDis_Reg = 0x24, /* Interrupt control disable */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?