cregit-Linux how code gets into the kernel

Release 4.11 drivers/atm/lanai.c

Directory: drivers/atm
/* 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.
 *
 * 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/slab.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/dma-mapping.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_DEVICE_ID_EF_ATM_LANAI2,
	
lanaihb	= PCI_DEVICE_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;
/* 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; for_each_set_bit(vci, lp, NUM_VCI) func(lanai, vci); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds3061.22%125.00%
Chas Williams1224.49%125.00%
Akinobu Mita612.24%125.00%
Mitchell Blank Jr.12.04%125.00%
Total49100.00%4100.00%

/* -------------------- 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 = dma_alloc_coherent(&pci->dev, size, &buf->dmaaddr, GFP_KERNEL); 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); }

Contributors

PersonTokensPropCommitsCommitProp
Chas Williams10959.24%266.67%
Linus Torvalds7540.76%133.33%
Total184100.00%3100.00%

/* 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); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds3397.06%150.00%
Chas Williams12.94%150.00%
Total34100.00%2100.00%


static void lanai_buf_deallocate(struct lanai_buffer *buf, struct pci_dev *pci) { if (buf->start != NULL) { dma_free_coherent(&pci->dev, lanai_buf_size(buf), buf->start, buf->dmaaddr); buf->start = buf->end = buf->ptr = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Chas Williams5081.97%266.67%
Linus Torvalds1118.03%133.33%
Total61100.00%3100.00%

/* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Chas Williams2455.81%150.00%
Linus Torvalds1944.19%150.00%
Total43100.00%2100.00%

/* -------------------- 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 */ Status_Reg = 0x28, /* Status */ #define STATUS_PROMDATA (0x00000001) /* PROM_DATA pin */ #define STATUS_WAITING (0x00000002) /* Interrupt being delayed */ #define STATUS_SOOL (0x00000004) /* SOOL alarm */ #define STATUS_LOCD (0x00000008) /* LOCD alarm */ #define STATUS_LED (0x00000010) /* LED (HAPPI) output */ #define STATUS_GPIN (0x00000020) /* GPIN pin */ #define STATUS_BUTTBUSY (0x00000040) /* Butt register is pending */ Config1_Reg = 0x2C, /* Config word 1; bits: */ #define CONFIG1_PROMDATA (0x00000001) /* PROM_DATA pin */ #define CONFIG1_PROMCLK (0x00000002) /* PROM_CLK pin */ #define CONFIG1_SET_READMODE(x) ((x)*0x004) /* PCI BM reads; values: */ #define READMODE_PLAIN (0) /* Plain memory read */ #define READMODE_LINE (2) /* Memory read line */ #define READMODE_MULTIPLE (3) /* Memory read multiple */ #define CONFIG1_DMA_ENABLE (0x00000010) /* Turn on DMA */ #define CONFIG1_POWERDOWN (0x00000020) /* Turn off clocks */ #define CONFIG1_SET_LOOPMODE(x) ((x)*0x080) /* Clock&loop mode; values: */ #define LOOPMODE_NORMAL (0) /* Normal - no loop */ #define LOOPMODE_TIME (1) #define LOOPMODE_DIAG (2) #define LOOPMODE_LINE (3) #define CONFIG1_MASK_LOOPMODE (0x00000180) #define CONFIG1_SET_LEDMODE(x) ((x)*0x0200) /* Mode of LED; values: */ #define LEDMODE_NOT_SOOL (0) /* !SOOL */ #define LEDMODE_OFF (1) /* 0 */ #define LEDMODE_ON (2) /* 1 */ #define LEDMODE_NOT_LOCD (3) /* !LOCD */ #define LEDMORE_GPIN (4) /* GPIN */ #define LEDMODE_NOT_GPIN (7) /* !GPIN */ #define CONFIG1_MASK_LEDMODE (0x00000E00) #define CONFIG1_GPOUT1 (0x00001000) /* Toggle for reset */ #define CONFIG1_GPOUT2 (0x00002000) /* Loopback PHY */ #define CONFIG1_GPOUT3 (0x00004000) /* Loopback lanai */ Config2_Reg = 0x30, /* Config word 2; bits: */ #define CONFIG2_HOWMANY (0x00000001) /* >512 VCIs? */ #define CONFIG2_PTI7_MODE (0x00000002) /* Make PTI=7 RM, not OAM */ #define CONFIG2_VPI_CHK_DIS (0x00000004) /* Ignore RX VPI value */ #define CONFIG2_HEC_DROP (0x00000008) /* Drop cells w/ HEC errors */ #define CONFIG2_VCI0_NORMAL (0x00000010) /* Treat VCI=0 normally */ #define CONFIG2_CBR_ENABLE (0x00000020) /* Deal with CBR traffic */ #define CONFIG2_TRASH_ALL (0x00000040) /* Trashing incoming cells */ #define CONFIG2_TX_DISABLE (0x00000080) /* Trashing outgoing cells */ #define CONFIG2_SET_TRASH (0x00000100) /* Turn trashing on */ Statistics_Reg = 0x34, /* Statistics; bits: */ #define STATS_GET_FIFO_OVFL(x) (((x)>> 0)&0xFF) /* FIFO overflowed */ #define STATS_GET_HEC_ERR(x) (((x)>> 8)&0xFF) /* HEC was bad */ #define STATS_GET_BAD_VCI(x) (((x)>>16)&0xFF) /* VCI not open */ #define STATS_GET_BUF_OVFL(x) (((x)>>24)&0xFF) /* VCC buffer full */ ServiceStuff_Reg = 0x38, /* Service stuff; bits: */ #define SSTUFF_SET_SIZE(x) ((x)*0x20000000) /* size of service buffer */ #define SSTUFF_SET_ADDR(x) ((x)>>8) /* set address of buffer */ ServWrite_Reg = 0x3C, /* ServWrite Pointer */ ServRead_Reg = 0x40, /* ServRead Pointer */ TxDepth_Reg = 0x44, /* FIFO Transmit Depth */ Butt_Reg = 0x48, /* Butt register */ CBR_ICG_Reg = 0x50, CBR_PTR_Reg = 0x54, PingCount_Reg = 0x58, /* Ping count */ DMA_Addr_Reg = 0x5C /* DMA address */ };
static inline bus_addr_t reg_addr(const struct lanai_dev *lanai, enum lanai_register reg) { return lanai->base + reg; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds24100.00%1100.00%
Total24100.00%1100.00%


static inline u32 reg_read(const struct lanai_dev *lanai, enum lanai_register reg) { u32 t; t = readl(reg_addr(lanai, reg)); RWDEBUG("R [0x%08X] 0x%02X = 0x%08X\n", (unsigned int) lanai->base, (int) reg, t); return t; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds55100.00%1100.00%
Total55100.00%1100.00%


static inline void reg_write(const struct lanai_dev *lanai, u32 val, enum lanai_register reg) { RWDEBUG("W [0x%08X] 0x%02X < 0x%08X\n", (unsigned int) lanai->base, (int) reg, val); writel(val, reg_addr(lanai, reg)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds52100.00%1100.00%
Total52100.00%1100.00%


static inline void conf1_write(const struct lanai_dev *lanai) { reg_write(lanai, lanai->conf1, Config1_Reg); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds24100.00%1100.00%
Total24100.00%1100.00%


static inline void conf2_write(const struct lanai_dev *lanai) { reg_write(lanai, lanai->conf2, Config2_Reg); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds24100.00%1100.00%
Total24100.00%1100.00%

/* Same as conf2_write(), but defers I/O if we're powered down */
static inline void conf2_write_if_powerup(const struct lanai_dev *lanai) { #ifdef USE_POWERDOWN if (unlikely((lanai->conf1 & CONFIG1_POWERDOWN) != 0)) return; #endif /* USE_POWERDOWN */ conf2_write(lanai); }

Contributors

PersonTokensPropCommitsCommitProp
Chas Williams40100.00%1100.00%
Total40100.00%1100.00%


static inline void reset_board(const struct lanai_dev *lanai) { DPRINTK("about to reset board\n"); reg_write(lanai, 0, Reset_Reg); /* * If we don't delay a little while here then we can end up * leaving the card in a VERY weird state and lock up the * PCI bus. This isn't documented anywhere but I've convinced * myself after a lot of painful experimentation */ udelay(5); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds33100.00%1100.00%
Total33100.00%1100.00%

/* -------------------- CARD SRAM UTILITIES: */ /* The SRAM is mapped into normal PCI memory space - the only catch is * that it is only 16-bits wide but must be accessed as 32-bit. The * 16 high bits will be zero. We don't hide this, since they get * programmed mostly like discrete registers anyway */ #define SRAM_START (0x20000) #define SRAM_BYTES (0x20000) /* Again, half don't really exist */
static inline bus_addr_t sram_addr(const struct lanai_dev *lanai, int offset) { return lanai->base + SRAM_START + offset; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds25100.00%1100.00%
Total25100.00%1100.00%


static inline u32 sram_read(const struct lanai_dev *lanai, int offset) { return readl(sram_addr(lanai, offset)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds27100.00%1100.00%
Total27100.00%1100.00%


static inline void sram_write(const struct lanai_dev *lanai, u32 val, int offset) { writel(val, sram_addr(lanai, offset)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds31100.00%1100.00%
Total31100.00%1100.00%


static int sram_test_word(const struct lanai_dev *lanai, int offset, u32 pattern) { u32 readback; sram_write(lanai, pattern, offset); readback = sram_read(lanai, offset); if (likely(readback == pattern)) return 0; printk(KERN_ERR DEV_LABEL "(itf %d): SRAM word at %d bad: wrote 0x%X, read 0x%X\n", lanai->number, offset, (unsigned int) pattern, (unsigned int) readback); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds6492.75%133.33%
Chas Williams57.25%266.67%
Total69100.00%3100.00%


static int sram_test_pass(const struct lanai_dev *lanai, u32 pattern) { int offset, result = 0; for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4) result = sram_test_word(lanai, offset, pattern); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds54100.00%1100.00%
Total54100.00%1100.00%


static int sram_test_and_clear(const struct lanai_dev *lanai) { #ifdef FULL_MEMORY_TEST int result; DPRINTK("testing SRAM\n"); if ((result = sram_test_pass(lanai, 0x5555)) != 0) return result; if ((result = sram_test_pass(lanai, 0xAAAA)) != 0) return result; #endif DPRINTK("clearing SRAM\n"); return sram_test_pass(lanai, 0x0000); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds74100.00%1100.00%
Total74100.00%1100.00%

/* -------------------- CARD-BASED VCC TABLE UTILITIES: */ /* vcc table */ enum lanai_vcc_offset { vcc_rxaddr1 = 0x00, /* Location1, plus bits: */ #define RXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of RX buffer */ #define RXADDR1_SET_RMMODE(x) ((x)*0x00800) /* RM cell action; values: */ #define RMMODE_TRASH (0) /* discard */ #define RMMODE_PRESERVE (1) /* input as AAL0 */ #define RMMODE_PIPE (2) /* pipe to coscheduler */ #define RMMODE_PIPEALL (3) /* pipe non-RM too */ #define RXADDR1_OAM_PRESERVE (0x00002000) /* Input OAM cells as AAL0 */ #define RXADDR1_SET_MODE(x) ((x)*0x0004000) /* Reassembly mode */ #define RXMODE_TRASH (0) /* discard */ #define RXMODE_AAL0 (1) /* non-AAL5 mode */ #define RXMODE_AAL5 (2) /* AAL5, intr. each PDU */ #define RXMODE_AAL5_STREAM (3) /* AAL5 w/o per-PDU intr */ vcc_rxaddr2 = 0x04, /* Location2 */ vcc_rxcrc1 = 0x08, /* RX CRC claculation space */ vcc_rxcrc2 = 0x0C, vcc_rxwriteptr = 0x10, /* RX writeptr, plus bits: */ #define RXWRITEPTR_LASTEFCI (0x00002000) /* Last PDU had EFCI bit */ #define RXWRITEPTR_DROPPING (0x00004000) /* Had error, dropping */ #define RXWRITEPTR_TRASHING (0x00008000) /* Trashing */ vcc_rxbufstart = 0x14, /* RX bufstart, plus bits: */ #define RXBUFSTART_CLP (0x00004000) #define RXBUFSTART_CI (0x00008000) vcc_rxreadptr = 0x18, /* RX readptr */ vcc_txicg = 0x1C, /* TX ICG */ vcc_txaddr1 = 0x20, /* Location1, plus bits: */ #define TXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of TX buffer */ #define TXADDR1_ABR (0x00008000) /* use ABR (doesn't work) */ vcc_txaddr2 = 0x24, /* Location2 */ vcc_txcrc1 = 0x28, /* TX CRC claculation space */ vcc_txcrc2 = 0x2C, vcc_txreadptr = 0x30, /* TX Readptr, plus bits: */ #define TXREADPTR_GET_PTR(x) ((x)&0x01FFF) #define TXREADPTR_MASK_DELTA (0x0000E000) /* ? */ vcc_txendptr = 0x34, /* TX Endptr, plus bits: */ #define TXENDPTR_CLP (0x00002000) #define TXENDPTR_MASK_PDUMODE (0x0000C000) /* PDU mode; values: */ #define PDUMODE_AAL0 (0*0x04000) #define PDUMODE_AAL5 (2*0x04000) #define PDUMODE_AAL5STREAM (3*0x04000) vcc_txwriteptr = 0x38, /* TX Writeptr */ #define TXWRITEPTR_GET_PTR(x) ((x)&0x1FFF) vcc_txcbr_next = 0x3C /* # of next CBR VCI in ring */ #define TXCBR_NEXT_BOZO (0x00008000) /* "bozo bit" */ }; #define CARDVCC_SIZE (0x40)
static inline bus_addr_t cardvcc_addr(const struct lanai_dev *lanai, vci_t vci) { return sram_addr(lanai, vci * CARDVCC_SIZE); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds26100.00%1100.00%
Total26100.00%1100.00%


static inline u32 cardvcc_read(const struct lanai_vcc *lvcc, enum lanai_vcc_offset offset) { u32 val; APRINTK(lvcc->vbase != NULL, "cardvcc_read: unbound vcc!\n"); val= readl(lvcc->vbase + offset); RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n", lvcc->vci, (int) offset, val); return val; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds6098.36%150.00%
Chas Williams11.64%150.00%
Total61100.00%2100.00%


static inline void cardvcc_write(const struct lanai_vcc *lvcc, u32 val, enum lanai_vcc_offset offset) { APRINTK(lvcc->vbase != NULL, "cardvcc_write: unbound vcc!\n"); APRINTK((val & ~0xFFFF) == 0, "cardvcc_write: bad val 0x%X (vci=%d, addr=0x%02X)\n", (unsigned int) val, lvcc->vci, (unsigned int) offset); RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", lvcc->vci, (unsigned int) offset, (unsigned int) val); writel(val, lvcc->vbase + offset); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds8288.17%133.33%
Chas Williams1111.83%266.67%
Total93100.00%3100.00%

/* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */ /* How many bytes will an AAL5 PDU take to transmit - remember that: * o we need to add 8 bytes for length, CPI, UU, and CRC * o we need to round up to 48 bytes for cells */
static inline int aal5_size(int size) { int cells = (size + 8 + 47) / 48; return cells * 48; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds28100.00%1100.00%
Total28100.00%1100.00%

/* -------------------- FREE AN ATM SKB: */
static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb) { if (atmvcc->pop != NULL) atmvcc->pop(atmvcc, skb); else dev_kfree_skb_any(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds40100.00%1100.00%
Total40100.00%1100.00%

/* -------------------- TURN VCCS ON AND OFF: */
static void host_vcc_start_rx(const struct lanai_vcc *lvcc) { u32 addr1; if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) { dma_addr_t dmaaddr = lvcc->rx.buf.dmaaddr; cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1); cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2); cardvcc_write(lvcc, 0, vcc_rxwriteptr); cardvcc_write(lvcc, 0, vcc_rxbufstart); cardvcc_write(lvcc, 0, vcc_rxreadptr); cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_rxaddr2); addr1 = ((dmaaddr >> 8) & 0xFF) | RXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->rx.buf))| RXADDR1_SET_RMMODE(RMMODE_TRASH) | /* ??? */ /* RXADDR1_OAM_PRESERVE | --- no OAM support yet */ RXADDR1_SET_MODE(RXMODE_AAL5); } else addr1 = RXADDR1_SET_RMMODE(RMMODE_PRESERVE) | /* ??? */ RXADDR1_OAM_PRESERVE | /* ??? */ RXADDR1_SET_MODE(RXMODE_AAL0); /* This one must be last! */ cardvcc_write(lvcc, addr1, vcc_rxaddr1); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds16398.19%150.00%
Chas Williams31.81%150.00%
Total166100.00%2100.00%


static void host_vcc_start_tx(const struct lanai_vcc *lvcc) { dma_addr_t dmaaddr = lvcc->tx.buf.dmaaddr; cardvcc_write(lvcc, 0, vcc_txicg); cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1); cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2); cardvcc_write(lvcc, 0, vcc_txreadptr); cardvcc_write(lvcc, 0, vcc_txendptr); cardvcc_write(lvcc, 0, vcc_txwriteptr); cardvcc_write(lvcc, (lvcc->tx.atmvcc->qos.txtp.traffic_class == ATM_CBR) ? TXCBR_NEXT_BOZO | lvcc->vci : 0, vcc_txcbr_next); cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_txaddr2); cardvcc_write(lvcc, ((dmaaddr >> 8) & 0xFF) | TXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->tx.buf)), vcc_txaddr1); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds15098.04%150.00%
Chas Williams31.96%150.00%
Total153100.00%2100.00%

/* Shutdown receiving on card */
static void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc) { if (lvcc->vbase == NULL) /* We were never bound to a VCI */ return; /* 15.1.1 - set to trashing, wait one cell time (15us) */ cardvcc_write(lvcc, RXADDR1_SET_RMMODE(RMMODE_TRASH) | RXADDR1_SET_MODE(RXMODE_TRASH), vcc_rxaddr1); udelay(15); /* 15.1.2 - clear rest of entries */ cardvcc_write(lvcc, 0, vcc_rxaddr2); cardvcc_write(lvcc, 0, vcc_rxcrc1); cardvcc_write(lvcc, 0, vcc_rxcrc2); cardvcc_write(lvcc, 0, vcc_rxwriteptr); cardvcc_write(lvcc, 0, vcc_rxbufstart); cardvcc_write(lvcc, 0, vcc_rxreadptr); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds9999.00%150.00%
Chas Williams11.00%150.00%
Total100100.00%2100.00%

/* Shutdown transmitting on card. * Unfortunately the lanai needs us to wait until all the data * drains out of the buffer before we can dealloc it, so this * can take awhile -- up to 370ms for a full 128KB buffer * assuming everone else is quiet. In theory the time is * boundless if there's a CBR VCC holding things up. */
static void lanai_shutdown_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc) { struct sk_buff *skb; unsigned long flags, timeout; int read, write, lastread = -1; APRINTK(!in_interrupt(), "lanai_shutdown_tx_vci called w/o process context!\n"); if (lvcc->vbase == NULL) /* We were never bound to a VCI */ return; /* 15.2.1 - wait for queue to drain */ while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL) lanai_free_skb(lvcc->tx.atmvcc, skb); read_lock_irqsave(&vcc_sklist_lock, flags); __clear_bit(lvcc->vci, lanai->backlog_vccs); read_unlock_irqrestore(&vcc_sklist_lock, flags); /* * We need to wait for the VCC to drain but don't wait forever. We * give each 1K of buffer size 1/128th of a second to clear out. * TODO: maybe disable CBR if we're about to timeout? */ timeout = jiffies + (((lanai_buf_size(&lvcc->tx.buf) / 1024) * HZ) >> 7); write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr)); for (;;) { read = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); if (read == write && /* Is TX buffer empty? */ (lvcc->tx.atmvcc->qos.txtp.traffic_class != ATM_CBR || (cardvcc_read(lvcc, vcc_txcbr_next) & TXCBR_NEXT_BOZO) == 0)) break; if (read !=