📄 lanai.c
字号:
/* lanai.c -- Copyright 1999 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're only set up to compile as a module currently. i.e. * you should put the source in drivers/atm/lanai.c and then * just do "make drivers/atm/lanai.o" from the main * source directory. This will produce a drivers/atm/lanai.o * file suitable for insmod'ing * * 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.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>#ifndef PCI_VENDOR_ID_EF_ATM_LANAI2/* These need to eventually go into <linux/pci.h> - they're here for now */#define PCI_VENDOR_ID_EF_ATM_LANAI2 0x0003#define PCI_VENDOR_ID_EF_ATM_LANAIHB 0x0005#endif/* -------------------- 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 (!(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 unsigned long bus_addr_t;/* A bitfield large enough for NUM_VCI */#define VCI_BITFIELD_NELEM ((NUM_VCI + BITS_PER_LONG - 1) / BITS_PER_LONG)typedef struct { unsigned long ul[VCI_BITFIELD_NELEM];} vci_bitfield;/* 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 */ int order; /* log2(size/PAGE_SIZE) */};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; struct sk_buff *inprogress; /* We're streaming this PDU */ unsigned char *pptr; /* Where we are in above */ int inprogleft; /* Bytes left to send "inprogress" */ 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_novcc_rx; unsigned service_novcc_tx; 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; vci_bitfield backlog_vccs; /* VCCs that are backlogged */ vci_bitfield transmit_ready; /* VCCs that have 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 txlock; 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>) */};/* -------------------- VCI_BITFIELD UTILITIES: *//* * These functions assume that BITS_PER_LONG is a power of two, which * should be safe */#if (BITS_PER_LONG & (BITS_PER_LONG - 1))#error lanai driver requires type long to have a power of two number of bits#endif/* * In vci_bitfield_{set,clear} we do the operation in three * parts to ensure that gcc doesn't cast anything down to * 32 bits (and then sign extend them later) on 64-bit * platforms like the alpha */static inline void vci_bitfield_set(vci_bitfield *bf, vci_t vci){ unsigned long bit = 1; bit <<= (unsigned long) (vci & (BITS_PER_LONG - 1)); bf->ul[vci / BITS_PER_LONG] |= bit;}static inline void vci_bitfield_clear(vci_bitfield *bf, vci_t vci){ unsigned long bit = 1; bit <<= (unsigned long) (vci & (BITS_PER_LONG - 1)); bf->ul[vci / BITS_PER_LONG] &= ~bit;}static inline void vci_bitfield_init(vci_bitfield *bf){ memset(bf, 0, sizeof(*bf));}static void vci_bitfield_iterate(struct lanai_dev *lanai, const vci_bitfield *bf, void (*func)(struct lanai_dev *,vci_t vci)){ vci_t vci; unsigned long mask; const unsigned long *lp = &(bf->ul[0]); for (vci = 0; vci < NUM_VCI; lp++) if (*lp == 0) vci += BITS_PER_LONG; else for (mask = 1; mask != 0; mask <<= 1, vci++) if (*lp & mask) func(lanai, vci);}/* -------------------- BUFFER UTILITIES: *//* * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes - * we assume that any page allocation will do. I'm sure this is * never going to be a problem, but it's good to document assumtions */#if PAGE_SIZE < 1024#error PAGE_SIZE too small to support LANAI chipset#endif/* * We also assume that the maximum buffer size will be some number * of whole pages, although that wouldn't be too hard to fix */#if PAGE_SIZE > (128 * 1024)#error PAGE_SIZE too large to support LANAI chipset#endif/* Convert a size to "order" for __get_free_pages */static int bytes_to_order(int bytes){ int order = 0; if (bytes > (128 * 1024)) bytes = 128 * 1024; /* Max buffer size for lanai */ while ((PAGE_SIZE << order) < bytes) order++; return order;}/* * Allocate a buffer in host RAM for service list, RX, or TX
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -