lanai.c revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* lanai.c -- Copyright 1999-2003 by Mitchell Blank Jr <mitch@sfgoth.com> 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver supports ATM cards based on the Efficient "Lanai" 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chipset such as the Speedstream 3010 and the ENI-25p. The 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Speedstream 3060 is currently not supported since we don't 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have the code to drive the on-board Alcatel DSL chipset (yet). 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Thanks to Efficient for supporting this project with hardware, 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * documentation, and by answering my questions. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Things not working yet: 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o We don't support the Speedstream 3060 yet - this card has 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an on-board DSL modem chip by Alcatel and the driver will 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * need some extra code added to handle it 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o Note that due to limitations of the Lanai only one VCC can be 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in CBR at once 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o We don't currently parse the EEPROM at all. The code is all 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there as per the spec, but it doesn't actually work. I think 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there may be some issues with the docs. Anyway, do NOT 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable it yet - bugs in that code may actually damage your 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware! Because of this you should hardware an ESI before 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * trying to use this in a LANE or MPOA environment. 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o AAL0 is stubbed in but the actual rx/tx path isn't written yet: 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vcc_tx_aal0() needs to send or queue a SKB 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vcc_tx_unqueue_aal0() needs to attempt to send queued SKBs 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vcc_rx_aal0() needs to handle AAL0 interrupts 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This isn't too much work - I just wanted to get other things 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * done first. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o lanai_change_qos() isn't written yet 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o There aren't any ioctl's yet -- I'd like to eventually support 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setting loopback and LED modes that way. (see lanai_ioctl) 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o If the segmentation engine or DMA gets shut down we should restart 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * card as per section 17.0i. (see lanai_reset) 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o setsockopt(SO_CIRANGE) isn't done (although despite what the 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * API says it isn't exactly commonly implemented) 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Version history: 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v.1.00 -- 26-JUL-2003 -- PCI/DMA updates 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v.0.02 -- 11-JAN-2000 -- Endian fixes 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v.0.01 -- 30-NOV-1999 -- Initial release 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atmdev.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/dma-mapping.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- TUNABLE PARAMATERS: */ 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maximum number of VCIs per card. Setting it lower could theoretically 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * save some memory, but since we allocate our vcc list with get_free_pages, 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's not really likely for most architectures 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NUM_VCI (1024) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable extra debugging 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Debug _all_ register operations with card, except the memory test. 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also disables the timed poll to prevent extra chattiness. This 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isn't for normal use 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_RW 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The programming guide specifies a full test of the on-board SRAM 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at initialization time. Undefine to remove this 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FULL_MEMORY_TEST 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the number of (4 byte) service entries that we will 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to allocate at startup. Note that we will end up with 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one PAGE_SIZE's worth regardless of what this is set to 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_ENTRIES (1024) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We normally read the onboard EEPROM in order to discover our MAC 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address. Undefine to _not_ do this 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* #define READ_EEPROM */ /* ***DONT ENABLE YET*** */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option (also) */ 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Depth of TX fifo (in 128 byte units; range 2-31) 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Smaller numbers are better for network latency 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Larger numbers are better for PCI latency 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I'm really sure where the best tradeoff is, but the BSD driver uses 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 7 and it seems to work ok. 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_FIFO_DEPTH (7) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * How often (in jiffies) we will try to unstick stuck connections - 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shouldn't need to happen much 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANAI_POLL_PERIOD (10*HZ) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When allocating an AAL5 receiving buffer, try to make it at least 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * large enough to hold this many max_sdu sized PDUs 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AAL5_RX_MULTIPLIER (3) 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Same for transmitting buffer 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AAL5_TX_MULTIPLIER (3) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When allocating an AAL0 transmiting buffer, how many cells should fit. 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remember we'll end up with a PAGE_SIZE of them anyway, so this isn't 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * really critical 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AAL0_TX_MULTIPLIER (40) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * How large should we make the AAL0 receiving buffer. Remember that this 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is shared between all AAL0 VC's 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AAL0_RX_BUFFER_SIZE (PAGE_SIZE) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should we use Lanai's "powerdown" feature when no vcc's are bound? 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* #define USE_POWERDOWN */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: make above a module load-time option (also) */ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- DEBUGGING AIDS: */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEV_LABEL "lanai" 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(format, args...) \ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG DEV_LABEL ": " format, ##args) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define APRINTK(truth, format, args...) \ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { \ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(!(truth))) \ 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL ": " format, ##args); \ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* !DEBUG */ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(format, args...) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define APRINTK(truth, format, args...) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* DEBUG */ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_RW 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RWDEBUG(format, args...) \ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG DEV_LABEL ": " format, ##args) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* !DEBUG_RW */ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RWDEBUG(format, args...) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- DATA DEFINITIONS: */ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANAI_MAPPING_SIZE (0x40000) 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANAI_EEPROM_SIZE (128) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef int vci_t; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef void __iomem *bus_addr_t; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DMA buffer in host memory for TX, RX, or service list. */ 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_buffer { 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *start; /* From get_free_pages */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *end; /* One past last byte */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *ptr; /* Pointer to current host location */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dmaaddr; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_vcc_stats { 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned rx_nomem; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds union { 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned rx_badlen; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_trash; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_stream; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_rxcrc; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } aal5; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } aal0; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } x; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_dev; /* Forward declaration */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the card-specific per-vcc data. Note that unlike some other 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers there is NOT a 1-to-1 correspondance between these and 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * atm_vcc's - each one of these represents an actual 2-way vcc, but 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an atm_vcc can be 1-way and share with a 1-way vcc in the other 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * direction. To make it weirder, there can even be 0-way vccs 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bound to us, waiting to do a change_qos 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_vcc { 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_addr_t vbase; /* Base of VCC's registers */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc_stats stats; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nref; /* # of atm_vcc's who reference us */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_t vci; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_buffer buf; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_vcc *atmvcc; /* atm_vcc who is receiver */ 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } rx; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_buffer buf; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_vcc *atmvcc; /* atm_vcc who is transmitter */ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int endptr; /* last endptr from service entry */ 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff_head backlog; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*unqueue)(struct lanai_dev *, struct lanai_vcc *, int); 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } tx; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum lanai_type { 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai2 = PCI_VENDOR_ID_EF_ATM_LANAI2, 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanaihb = PCI_VENDOR_ID_EF_ATM_LANAIHB 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_dev_stats { 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned ovfl_trash; /* # of cells dropped - buffer overflow */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned vci_trash; /* # of cells dropped - closed vci */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned hec_err; /* # of cells dropped - bad HEC */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned atm_ovfl; /* # of cells dropped - rx fifo overflow */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_parity_detect; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_serr_set; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_master_abort; 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_m_target_abort; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_s_target_abort; 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned pcierr_master_parity; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_notx; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_norx; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned service_rxnotaal5; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned dma_reenable; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned card_reset; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lanai_dev { 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus_addr_t base; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev_stats stats; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_buffer service; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc **vccs; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nbound; /* number of bound vccs */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum lanai_type type; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_t num_vci; /* Currently just NUM_VCI */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 eeprom[LANAI_EEPROM_SIZE]; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 serialno, magicno; 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pci; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_BITMAP(backlog_vccs, NUM_VCI); /* VCCs with tx backlog */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DECLARE_BITMAP(transmit_ready, NUM_VCI); /* VCCs with transmit space */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct timer_list timer; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int naal0; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_buffer aal0buf; /* AAL0 RX buffers */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 conf1, conf2; /* CONFIG[12] registers */ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 status; /* STATUS register */ 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t endtxlock; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t servicelock; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_vcc *cbrvcc; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int number; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int board_rev; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 pci_revision; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO - look at race conditions with maintence of conf1/conf2 */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO - transmit locking: should we use _irq not _irqsave? */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO - organize above in some rational fashion (see <asm/cache.h>) */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Each device has two bitmaps for each VCC (baclog_vccs and transmit_ready) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function iterates one of these, calling a given function for each 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vci with their bit set 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vci_bitfield_iterate(struct lanai_dev *lanai, 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*const*/ unsigned long *lp, 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*func)(struct lanai_dev *,vci_t vci)) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_t vci = find_first_bit(lp, NUM_VCI); 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (vci < NUM_VCI) { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds func(lanai, vci); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci = find_next_bit(lp, NUM_VCI, vci + 1); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- BUFFER UTILITIES: */ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes - 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * usually any page allocation will do. Just to be safe in case 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PAGE_SIZE is insanely tiny, though... 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANAI_PAGE_SIZE ((PAGE_SIZE >= 1024) ? PAGE_SIZE : 1024) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a buffer in host RAM for service list, RX, or TX 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns buf->start==NULL if no memory 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that the size will be rounded up 2^n bytes, and 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if we can't allocate that we'll settle for something smaller 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * until minbytes 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_buf_allocate(struct lanai_buffer *buf, 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t bytes, size_t minbytes, struct pci_dev *pci) 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes > (128 * 1024)) /* max lanai buffer size */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes = 128 * 1024; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (size = LANAI_PAGE_SIZE; size < bytes; size *= 2) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (minbytes < LANAI_PAGE_SIZE) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds minbytes = LANAI_PAGE_SIZE; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Technically we could use non-consistent mappings for 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * everything, but the way the lanai uses DMA memory would 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * make that a terrific pain. This is much simpler. 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->start = pci_alloc_consistent(pci, size, &buf->dmaaddr); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf->start != NULL) { /* Success */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Lanai requires 256-byte alignment of DMA bufs */ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0, 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "bad dmaaddr: 0x%lx\n", 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) buf->dmaaddr); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->ptr = buf->start; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->end = (u32 *) 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (&((unsigned char *) buf->start)[size]); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(buf->start, 0, size); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size /= 2; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (size >= minbytes); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* size of buffer in bytes */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline size_t lanai_buf_size(const struct lanai_buffer *buf) 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((unsigned long) buf->end) - ((unsigned long) buf->start); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_buf_deallocate(struct lanai_buffer *buf, 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pci) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf->start != NULL) { 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_free_consistent(pci, lanai_buf_size(buf), 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->start, buf->dmaaddr); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf->start = buf->end = buf->ptr = NULL; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* size of buffer as "card order" (0=1k .. 7=128k) */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_buf_size_cardorder(const struct lanai_buffer *buf) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int order = get_order(lanai_buf_size(buf)) + (PAGE_SHIFT - 10); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This can only happen if PAGE_SIZE is gigantic, but just in case */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (order > 7) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds order = 7; 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return order; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- PORT I/O UTILITIES: */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Registers (and their bit-fields) */ 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum lanai_register { 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Reset_Reg = 0x00, /* Reset; read for chip type; bits: */ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RESET_GET_BOARD_REV(x) (((x)>> 0)&0x03) /* Board revision */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RESET_GET_BOARD_ID(x) (((x)>> 2)&0x03) /* Board ID */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BOARD_ID_LANAI256 (0) /* 25.6M adapter card */ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Endian_Reg = 0x04, /* Endian setting */ 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntStatus_Reg = 0x08, /* Interrupt status */ 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntStatusMasked_Reg = 0x0C, /* Interrupt status (masked) */ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntAck_Reg = 0x10, /* Interrupt acknowledge */ 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntAckMasked_Reg = 0x14, /* Interrupt acknowledge (masked) */ 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntStatusSet_Reg = 0x18, /* Get status + enable/disable */ 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntStatusSetMasked_Reg = 0x1C, /* Get status + en/di (masked) */ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntControlEna_Reg = 0x20, /* Interrupt control enable */ 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IntControlDis_Reg = 0x24, /* Interrupt control disable */ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Status_Reg = 0x28, /* Status */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_PROMDATA (0x00000001) /* PROM_DATA pin */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_WAITING (0x00000002) /* Interrupt being delayed */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_SOOL (0x00000004) /* SOOL alarm */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_LOCD (0x00000008) /* LOCD alarm */ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_LED (0x00000010) /* LED (HAPPI) output */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_GPIN (0x00000020) /* GPIN pin */ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATUS_BUTTBUSY (0x00000040) /* Butt register is pending */ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Config1_Reg = 0x2C, /* Config word 1; bits: */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_PROMDATA (0x00000001) /* PROM_DATA pin */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_PROMCLK (0x00000002) /* PROM_CLK pin */ 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_SET_READMODE(x) ((x)*0x004) /* PCI BM reads; values: */ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define READMODE_PLAIN (0) /* Plain memory read */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define READMODE_LINE (2) /* Memory read line */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define READMODE_MULTIPLE (3) /* Memory read multiple */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_DMA_ENABLE (0x00000010) /* Turn on DMA */ 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_POWERDOWN (0x00000020) /* Turn off clocks */ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_SET_LOOPMODE(x) ((x)*0x080) /* Clock&loop mode; values: */ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPMODE_NORMAL (0) /* Normal - no loop */ 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPMODE_TIME (1) 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPMODE_DIAG (2) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LOOPMODE_LINE (3) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_MASK_LOOPMODE (0x00000180) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_SET_LEDMODE(x) ((x)*0x0200) /* Mode of LED; values: */ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMODE_NOT_SOOL (0) /* !SOOL */ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMODE_OFF (1) /* 0 */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMODE_ON (2) /* 1 */ 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMODE_NOT_LOCD (3) /* !LOCD */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMORE_GPIN (4) /* GPIN */ 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LEDMODE_NOT_GPIN (7) /* !GPIN */ 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_MASK_LEDMODE (0x00000E00) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_GPOUT1 (0x00001000) /* Toggle for reset */ 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_GPOUT2 (0x00002000) /* Loopback PHY */ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG1_GPOUT3 (0x00004000) /* Loopback lanai */ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Config2_Reg = 0x30, /* Config word 2; bits: */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_HOWMANY (0x00000001) /* >512 VCIs? */ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_PTI7_MODE (0x00000002) /* Make PTI=7 RM, not OAM */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_VPI_CHK_DIS (0x00000004) /* Ignore RX VPI value */ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_HEC_DROP (0x00000008) /* Drop cells w/ HEC errors */ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_VCI0_NORMAL (0x00000010) /* Treat VCI=0 normally */ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_CBR_ENABLE (0x00000020) /* Deal with CBR traffic */ 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_TRASH_ALL (0x00000040) /* Trashing incoming cells */ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_TX_DISABLE (0x00000080) /* Trashing outgoing cells */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CONFIG2_SET_TRASH (0x00000100) /* Turn trashing on */ 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Statistics_Reg = 0x34, /* Statistics; bits: */ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATS_GET_FIFO_OVFL(x) (((x)>> 0)&0xFF) /* FIFO overflowed */ 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATS_GET_HEC_ERR(x) (((x)>> 8)&0xFF) /* HEC was bad */ 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATS_GET_BAD_VCI(x) (((x)>>16)&0xFF) /* VCI not open */ 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define STATS_GET_BUF_OVFL(x) (((x)>>24)&0xFF) /* VCC buffer full */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ServiceStuff_Reg = 0x38, /* Service stuff; bits: */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SSTUFF_SET_SIZE(x) ((x)*0x20000000) /* size of service buffer */ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SSTUFF_SET_ADDR(x) ((x)>>8) /* set address of buffer */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ServWrite_Reg = 0x3C, /* ServWrite Pointer */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ServRead_Reg = 0x40, /* ServRead Pointer */ 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TxDepth_Reg = 0x44, /* FIFO Transmit Depth */ 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Butt_Reg = 0x48, /* Butt register */ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CBR_ICG_Reg = 0x50, 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CBR_PTR_Reg = 0x54, 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PingCount_Reg = 0x58, /* Ping count */ 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA_Addr_Reg = 0x5C /* DMA address */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline bus_addr_t reg_addr(const struct lanai_dev *lanai, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum lanai_register reg) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lanai->base + reg; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 reg_read(const struct lanai_dev *lanai, 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum lanai_register reg) 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 t; 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = readl(reg_addr(lanai, reg)); 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RWDEBUG("R [0x%08X] 0x%02X = 0x%08X\n", (unsigned int) lanai->base, 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) reg, t); 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return t; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void reg_write(const struct lanai_dev *lanai, u32 val, 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum lanai_register reg) 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RWDEBUG("W [0x%08X] 0x%02X < 0x%08X\n", (unsigned int) lanai->base, 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) reg, val); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(val, reg_addr(lanai, reg)); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void conf1_write(const struct lanai_dev *lanai) 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, lanai->conf1, Config1_Reg); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void conf2_write(const struct lanai_dev *lanai) 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, lanai->conf2, Config2_Reg); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Same as conf2_write(), but defers I/O if we're powered down */ 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void conf2_write_if_powerup(const struct lanai_dev *lanai) 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely((lanai->conf1 & CONFIG1_POWERDOWN) != 0)) 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* USE_POWERDOWN */ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write(lanai); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void reset_board(const struct lanai_dev *lanai) 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("about to reset board\n"); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, 0, Reset_Reg); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we don't delay a little while here then we can end up 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * leaving the card in a VERY weird state and lock up the 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI bus. This isn't documented anywhere but I've convinced 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * myself after a lot of painful experimentation 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(5); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- CARD SRAM UTILITIES: */ 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The SRAM is mapped into normal PCI memory space - the only catch is 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that it is only 16-bits wide but must be accessed as 32-bit. The 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16 high bits will be zero. We don't hide this, since they get 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * programmed mostly like discrete registers anyway 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SRAM_START (0x20000) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SRAM_BYTES (0x20000) /* Again, half don't really exist */ 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline bus_addr_t sram_addr(const struct lanai_dev *lanai, int offset) 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lanai->base + SRAM_START + offset; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 sram_read(const struct lanai_dev *lanai, int offset) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return readl(sram_addr(lanai, offset)); 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void sram_write(const struct lanai_dev *lanai, 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val, int offset) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(val, sram_addr(lanai, offset)); 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sram_test_word( 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct lanai_dev *lanai, int offset, u32 pattern) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 readback; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sram_write(lanai, pattern, offset); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds readback = sram_read(lanai, offset); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (likely(readback == pattern)) 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(itf %d): SRAM word at %d bad: wrote 0x%X, read 0x%X\n", 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number, offset, 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) pattern, (unsigned int) readback); 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit sram_test_pass(const struct lanai_dev *lanai, u32 pattern) 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int offset, result = 0; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sram_test_word(lanai, offset, pattern); 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit sram_test_and_clear(const struct lanai_dev *lanai) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef FULL_MEMORY_TEST 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("testing SRAM\n"); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = sram_test_pass(lanai, 0x5555)) != 0) 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = sram_test_pass(lanai, 0xAAAA)) != 0) 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("clearing SRAM\n"); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sram_test_pass(lanai, 0x0000); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- CARD-BASED VCC TABLE UTILITIES: */ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* vcc table */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum lanai_vcc_offset { 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxaddr1 = 0x00, /* Location1, plus bits: */ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of RX buffer */ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXADDR1_SET_RMMODE(x) ((x)*0x00800) /* RM cell action; values: */ 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMMODE_TRASH (0) /* discard */ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMMODE_PRESERVE (1) /* input as AAL0 */ 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMMODE_PIPE (2) /* pipe to coscheduler */ 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMMODE_PIPEALL (3) /* pipe non-RM too */ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXADDR1_OAM_PRESERVE (0x00002000) /* Input OAM cells as AAL0 */ 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXADDR1_SET_MODE(x) ((x)*0x0004000) /* Reassembly mode */ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXMODE_TRASH (0) /* discard */ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXMODE_AAL0 (1) /* non-AAL5 mode */ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXMODE_AAL5 (2) /* AAL5, intr. each PDU */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXMODE_AAL5_STREAM (3) /* AAL5 w/o per-PDU intr */ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxaddr2 = 0x04, /* Location2 */ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxcrc1 = 0x08, /* RX CRC claculation space */ 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxcrc2 = 0x0C, 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxwriteptr = 0x10, /* RX writeptr, plus bits: */ 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXWRITEPTR_LASTEFCI (0x00002000) /* Last PDU had EFCI bit */ 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXWRITEPTR_DROPPING (0x00004000) /* Had error, dropping */ 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXWRITEPTR_TRASHING (0x00008000) /* Trashing */ 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxbufstart = 0x14, /* RX bufstart, plus bits: */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXBUFSTART_CLP (0x00004000) 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RXBUFSTART_CI (0x00008000) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rxreadptr = 0x18, /* RX readptr */ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txicg = 0x1C, /* TX ICG */ 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txaddr1 = 0x20, /* Location1, plus bits: */ 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of TX buffer */ 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXADDR1_ABR (0x00008000) /* use ABR (doesn't work) */ 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txaddr2 = 0x24, /* Location2 */ 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txcrc1 = 0x28, /* TX CRC claculation space */ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txcrc2 = 0x2C, 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txreadptr = 0x30, /* TX Readptr, plus bits: */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXREADPTR_GET_PTR(x) ((x)&0x01FFF) 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXREADPTR_MASK_DELTA (0x0000E000) /* ? */ 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txendptr = 0x34, /* TX Endptr, plus bits: */ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXENDPTR_CLP (0x00002000) 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXENDPTR_MASK_PDUMODE (0x0000C000) /* PDU mode; values: */ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PDUMODE_AAL0 (0*0x04000) 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PDUMODE_AAL5 (2*0x04000) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PDUMODE_AAL5STREAM (3*0x04000) 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txwriteptr = 0x38, /* TX Writeptr */ 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXWRITEPTR_GET_PTR(x) ((x)&0x1FFF) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txcbr_next = 0x3C /* # of next CBR VCI in ring */ 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TXCBR_NEXT_BOZO (0x00008000) /* "bozo bit" */ 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CARDVCC_SIZE (0x40) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline bus_addr_t cardvcc_addr(const struct lanai_dev *lanai, 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_t vci) 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sram_addr(lanai, vci * CARDVCC_SIZE); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 cardvcc_read(const struct lanai_vcc *lvcc, 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum lanai_vcc_offset offset) 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(lvcc->vbase != NULL, "cardvcc_read: unbound vcc!\n"); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val= readl(lvcc->vbase + offset); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n", 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vci, (int) offset, val); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void cardvcc_write(const struct lanai_vcc *lvcc, 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val, enum lanai_vcc_offset offset) 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(lvcc->vbase != NULL, "cardvcc_write: unbound vcc!\n"); 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((val & ~0xFFFF) == 0, 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cardvcc_write: bad val 0x%X (vci=%d, addr=0x%02X)\n", 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) val, lvcc->vci, (unsigned int) offset); 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vci, (unsigned int) offset, (unsigned int) val); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(val, lvcc->vbase + offset); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */ 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* How many bytes will an AAL5 PDU take to transmit - remember that: 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o we need to add 8 bytes for length, CPI, UU, and CRC 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * o we need to round up to 48 bytes for cells 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int aal5_size(int size) 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cells = (size + 8 + 47) / 48; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cells * 48; 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* How many bytes can we send if we have "space" space, assuming we have 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to send full cells 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int aal5_spacefor(int space) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cells = space / 48; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cells * 48; 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- FREE AN ATM SKB: */ 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb) 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->pop != NULL) 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmvcc->pop(atmvcc, skb); 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- TURN VCCS ON AND OFF: */ 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void host_vcc_start_rx(const struct lanai_vcc *lvcc) 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 addr1; 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) { 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dmaaddr = lvcc->rx.buf.dmaaddr; 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxwriteptr); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxbufstart); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxreadptr); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_rxaddr2); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr1 = ((dmaaddr >> 8) & 0xFF) | 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->rx.buf))| 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_RMMODE(RMMODE_TRASH) | /* ??? */ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* RXADDR1_OAM_PRESERVE | --- no OAM support yet */ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_MODE(RXMODE_AAL5); 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr1 = RXADDR1_SET_RMMODE(RMMODE_PRESERVE) | /* ??? */ 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_OAM_PRESERVE | /* ??? */ 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_MODE(RXMODE_AAL0); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This one must be last! */ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, addr1, vcc_rxaddr1); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void host_vcc_start_tx(const struct lanai_vcc *lvcc) 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dma_addr_t dmaaddr = lvcc->tx.buf.dmaaddr; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txicg); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1); 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txreadptr); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txendptr); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txwriteptr); 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lvcc->tx.atmvcc->qos.txtp.traffic_class == ATM_CBR) ? 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXCBR_NEXT_BOZO | lvcc->vci : 0, vcc_txcbr_next); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_txaddr2); 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((dmaaddr >> 8) & 0xFF) | 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->tx.buf)), 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_txaddr1); 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Shutdown receiving on card */ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc) 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->vbase == NULL) /* We were never bound to a VCI */ 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15.1.1 - set to trashing, wait one cell time (15us) */ 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_RMMODE(RMMODE_TRASH) | 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RXADDR1_SET_MODE(RXMODE_TRASH), vcc_rxaddr1); 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(15); 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15.1.2 - clear rest of entries */ 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxaddr2); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxcrc1); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxcrc2); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxwriteptr); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxbufstart); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_rxreadptr); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Shutdown transmitting on card. 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unfortunately the lanai needs us to wait until all the data 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drains out of the buffer before we can dealloc it, so this 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can take awhile -- up to 370ms for a full 128KB buffer 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assuming everone else is quiet. In theory the time is 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * boundless if there's a CBR VCC holding things up. 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_shutdown_tx_vci(struct lanai_dev *lanai, 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc) 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags, timeout; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int read, write, lastread = -1; 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(!in_interrupt(), 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "lanai_shutdown_tx_vci called w/o process context!\n"); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->vbase == NULL) /* We were never bound to a VCI */ 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15.2.1 - wait for queue to drain */ 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL) 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_free_skb(lvcc->tx.atmvcc, skb); 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock_irqsave(&vcc_sklist_lock, flags); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __clear_bit(lvcc->vci, lanai->backlog_vccs); 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock_irqrestore(&vcc_sklist_lock, flags); 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to wait for the VCC to drain but don't wait forever. We 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * give each 1K of buffer size 1/128th of a second to clear out. 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TODO: maybe disable CBR if we're about to timeout? 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = jiffies + 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((lanai_buf_size(&lvcc->tx.buf) / 1024) * HZ) >> 7); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr)); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read == write && /* Is TX buffer empty? */ 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lvcc->tx.atmvcc->qos.txtp.traffic_class != ATM_CBR || 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cardvcc_read(lvcc, vcc_txcbr_next) & 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXCBR_NEXT_BOZO) == 0)) 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read != lastread) { /* Has there been any progress? */ 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lastread = read; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout += HZ / 10; 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(time_after(jiffies, timeout))) { 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): Timed out on " 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "backlog closing vci %d\n", 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc->dev->number, lvcc->vci); 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("read, write = %d, %d\n", read, write); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(40); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15.2.2 - clear out all tx registers */ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txreadptr); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txwriteptr); 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txendptr); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txcrc1); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txcrc2); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txaddr2); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, 0, vcc_txaddr1); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- MANAGING AAL0 RX BUFFER: */ 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int aal0_buffer_allocate(struct lanai_dev *lanai) 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("aal0_buffer_allocate: allocating AAL0 RX buffer\n"); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_allocate(&lanai->aal0buf, AAL0_RX_BUFFER_SIZE, 80, 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->pci); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (lanai->aal0buf.start == NULL) ? -ENOMEM : 0; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void aal0_buffer_free(struct lanai_dev *lanai) 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("aal0_buffer_allocate: freeing AAL0 RX buffer\n"); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_deallocate(&lanai->aal0buf, lanai->pci); 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- EEPROM UTILITIES: */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Offsets of data in the EEPROM */ 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_COPYRIGHT (0) 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_COPYRIGHT_LEN (44) 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_CHECKSUM (62) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_CHECKSUM_REV (63) 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_MAC (64) 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_MAC_REV (70) 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_SERIAL (112) 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_SERIAL_REV (116) 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_MAGIC (120) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_MAGIC_REV (124) 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EEPROM_MAGIC_VALUE (0x5AB478D2) 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef READ_EEPROM 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Stub functions to use if EEPROM reading is disabled */ 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit eeprom_read(struct lanai_dev *lanai) 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL "(itf %d): *NOT* reading EEPROM\n", 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&lanai->eeprom[EEPROM_MAC], 0, 6); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit eeprom_validate(struct lanai_dev *lanai) 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->serialno = 0; 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->magicno = EEPROM_MAGIC_VALUE; 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* READ_EEPROM */ 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit eeprom_read(struct lanai_dev *lanai) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, address; 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 data; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tmp; 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define set_config1(x) do { lanai->conf1 = x; conf1_write(lanai); \ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (0) 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define clock_h() set_config1(lanai->conf1 | CONFIG1_PROMCLK) 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define clock_l() set_config1(lanai->conf1 &~ CONFIG1_PROMCLK) 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define data_h() set_config1(lanai->conf1 | CONFIG1_PROMDATA) 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define data_l() set_config1(lanai->conf1 &~ CONFIG1_PROMDATA) 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define pre_read() do { data_h(); clock_h(); udelay(5); } while (0) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define read_pin() (reg_read(lanai, Status_Reg) & STATUS_PROMDATA) 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define send_stop() do { data_l(); udelay(5); clock_h(); udelay(5); \ 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_h(); udelay(5); } while (0) 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start with both clock and data high */ 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_h(); clock_h(); udelay(5); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (address = 0; address < LANAI_EEPROM_SIZE; address++) { 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = (address << 1) | 1; /* Command=read + address */ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* send start bit */ 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_l(); udelay(5); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_l(); udelay(5); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 128; i != 0; i >>= 1) { /* write command out */ 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) | 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (data & i) ? CONFIG1_PROMDATA : 0; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->conf1 != tmp) { 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_config1(tmp); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(5); /* Let new data settle */ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_h(); udelay(5); clock_l(); udelay(5); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look for ack */ 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_h(); clock_h(); udelay(5); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_pin() != 0) 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; /* No ack seen */ 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_l(); udelay(5); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* read back result */ 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (data = 0, i = 7; i >= 0; i--) { 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_h(); clock_h(); udelay(5); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = (data << 1) | !!read_pin(); 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_l(); udelay(5); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* look again for ack */ 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data_h(); clock_h(); udelay(5); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_pin() == 0) 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; /* Spurious ack */ 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_l(); udelay(5); 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_stop(); 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[address] = data; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("EEPROM 0x%04X %02X\n", 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) address, (unsigned int) data); 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error: 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clock_l(); udelay(5); /* finish read */ 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds send_stop(); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): error reading EEPROM byte %d\n", 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number, address); 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef set_config1 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef clock_h 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef clock_l 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef data_h 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef data_l 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef pre_read 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef read_pin 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef send_stop 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* read a big-endian 4-byte value out of eeprom */ 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 eeprom_be4(const struct lanai_dev *lanai, int address) 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return be32_to_cpup((u32 *) (&lanai->eeprom[address])); 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Checksum/validate EEPROM contents */ 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit eeprom_validate(struct lanai_dev *lanai) 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, s; 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 v; 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 *e = lanai->eeprom; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First, see if we can get an ASCIIZ string out of the copyright */ 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = EEPROM_COPYRIGHT; 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i < (EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN); i++) 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (e[i] < 0x20 || e[i] > 0x7E) 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( i != EEPROM_COPYRIGHT && 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i != EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN && e[i] == '\0') 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("eeprom: copyright = \"%s\"\n", 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (char *) &e[EEPROM_COPYRIGHT]); 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("eeprom: copyright not found\n"); 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Validate checksum */ 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = s = 0; i < EEPROM_CHECKSUM; i++) 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s += e[i]; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s &= 0xFF; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s != e[EEPROM_CHECKSUM]) { 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM checksum bad " 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(wanted 0x%02X, got 0x%02X)\n", lanai->number, 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM]); 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s ^= 0xFF; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s != e[EEPROM_CHECKSUM_REV]) { 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM inverse checksum " 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "bad (wanted 0x%02X, got 0x%02X)\n", lanai->number, 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM_REV]); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify MAC address */ 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((e[EEPROM_MAC + i] ^ e[EEPROM_MAC_REV + i]) != 0xFF) { 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(itf %d) : EEPROM MAC addresses don't match " 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(0x%02X, inverse 0x%02X)\n", lanai->number, 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) e[EEPROM_MAC + i], 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) e[EEPROM_MAC_REV + i]); 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("eeprom: MAC address = %02X:%02X:%02X:%02X:%02X:%02X\n", 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e[EEPROM_MAC + 0], e[EEPROM_MAC + 1], e[EEPROM_MAC + 2], 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e[EEPROM_MAC + 3], e[EEPROM_MAC + 4], e[EEPROM_MAC + 5]); 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify serial number */ 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL); 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = eeprom_be4(lanai, EEPROM_SERIAL_REV); 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lanai->serialno ^ v) != 0xFFFFFFFF) { 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM serial numbers " 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) lanai->serialno, (unsigned int) v); 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("eeprom: Serial number = %d\n", (unsigned int) lanai->serialno); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify magic number */ 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->magicno = eeprom_be4(lanai, EEPROM_MAGIC); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = eeprom_be4(lanai, EEPROM_MAGIC_REV); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lanai->magicno ^ v) != 0xFFFFFFFF) { 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM magic numbers " 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->magicno, v); 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("eeprom: Magic number = 0x%08X\n", lanai->magicno); 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->magicno != EEPROM_MAGIC_VALUE) 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING DEV_LABEL "(itf %d): warning - EEPROM " 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "magic not what expected (got 0x%08X, not 0x%08X)\n", 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number, (unsigned int) lanai->magicno, 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) EEPROM_MAGIC_VALUE); 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* READ_EEPROM */ 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline const u8 *eeprom_mac(const struct lanai_dev *lanai) 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return &lanai->eeprom[EEPROM_MAC]; 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- INTERRUPT HANDLING UTILITIES: */ 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Interrupt types */ 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_STATS (0x00000002) /* Statistics counter overflow */ 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_SOOL (0x00000004) /* SOOL changed state */ 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_LOCD (0x00000008) /* LOCD changed state */ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_LED (0x00000010) /* LED (HAPPI) changed state */ 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_GPIN (0x00000020) /* GPIN changed state */ 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_PING (0x00000040) /* PING_COUNT fulfilled */ 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_WAKE (0x00000080) /* Lanai wants bus */ 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_CBR0 (0x00000100) /* CBR sched hit VCI 0 */ 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_LOCK (0x00000200) /* Service list overflow */ 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_MISMATCH (0x00000400) /* TX magic list mismatch */ 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_AAL0_STR (0x00000800) /* Non-AAL5 buffer half filled */ 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_AAL0 (0x00001000) /* Non-AAL5 data available */ 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_SERVICE (0x00002000) /* Service list entries available */ 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_TABORTSENT (0x00004000) /* Target abort sent by lanai */ 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_TABORTBM (0x00008000) /* Abort rcv'd as bus master */ 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_TIMEOUTBM (0x00010000) /* No response to bus master */ 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_PCIPARITY (0x00020000) /* Parity error on PCI */ 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sets of the above */ 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_ALL (0x0003FFFE) /* All interrupts */ 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_STATUS (0x0000003C) /* Some status pin changed */ 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_DMASHUT (0x00038000) /* DMA engine got shut down */ 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define INT_SEGSHUT (0x00000700) /* Segmentation got shut down */ 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 intr_pending(const struct lanai_dev *lanai) 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return reg_read(lanai, IntStatusMasked_Reg); 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void intr_enable(const struct lanai_dev *lanai, u32 i) 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, i, IntControlEna_Reg); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void intr_disable(const struct lanai_dev *lanai, u32 i) 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, i, IntControlDis_Reg); 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- CARD/PCI STATUS: */ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void status_message(int itf, const char *name, int status) 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static const char *onoff[2] = { "off to on", "on to off" }; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL "(itf %d): %s changed from %s\n", 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds itf, name, onoff[!status]); 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_check_status(struct lanai_dev *lanai) 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 new = reg_read(lanai, Status_Reg); 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 changes = new ^ lanai->status; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->status = new; 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define e(flag, name) \ 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (changes & flag) \ 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status_message(lanai->number, name, new & flag) 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(STATUS_SOOL, "SOOL"); 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(STATUS_LOCD, "LOCD"); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(STATUS_LED, "LED"); 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(STATUS_GPIN, "GPIN"); 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef e 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pcistatus_got(int itf, const char *name) 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL "(itf %d): PCI got %s error\n", itf, name); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pcistatus_check(struct lanai_dev *lanai, int clearonly) 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 s; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = pci_read_config_word(lanai->pci, PCI_STATUS, &s); 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != PCIBIOS_SUCCESSFUL) { 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't read PCI_STATUS: " 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%d\n", lanai->number, result); 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT | 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_PARITY; 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s == 0) 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = pci_write_config_word(lanai->pci, PCI_STATUS, s); 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != PCIBIOS_SUCCESSFUL) 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't write PCI_STATUS: " 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%d\n", lanai->number, result); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (clearonly) 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define e(flag, name, stat) \ 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s & flag) { \ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_got(lanai->number, name); \ 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lanai->stats.pcierr_##stat; \ 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_DETECTED_PARITY, "parity", parity_detect); 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_SIG_SYSTEM_ERROR, "signalled system", serr_set); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_REC_MASTER_ABORT, "master", master_abort); 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_REC_TARGET_ABORT, "master target", m_target_abort); 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_SIG_TARGET_ABORT, "slave", s_target_abort); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e(PCI_STATUS_PARITY, "master parity", master_parity); 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef e 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- VCC TX BUFFER UTILITIES: */ 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* space left in tx buffer in bytes */ 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int vcc_tx_space(const struct lanai_vcc *lvcc, int endptr) 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int r; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = endptr * 16; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r -= ((unsigned long) lvcc->tx.buf.ptr) - 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((unsigned long) lvcc->tx.buf.start); 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r -= 16; /* Leave "bubble" - if start==end it looks empty */ 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r < 0) 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r += lanai_buf_size(&lvcc->tx.buf); 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return r; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* test if VCC is currently backlogged */ 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int vcc_is_backlogged(/*const*/ struct lanai_vcc *lvcc) 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return !skb_queue_empty(&lvcc->tx.backlog); 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bit fields in the segmentation buffer descriptor */ 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DESCRIPTOR_MAGIC (0xD0000000) 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DESCRIPTOR_AAL5 (0x00008000) 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DESCRIPTOR_AAL5_STREAM (0x00004000) 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DESCRIPTOR_CLP (0x00002000) 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add 32-bit descriptor with its padding */ 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_tx_add_aal5_descriptor(struct lanai_vcc *lvcc, 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 flags, int len) 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pos; 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 0, 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_tx_add_aal5_descriptor: bad ptr=%p\n", lvcc->tx.buf.ptr); 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr += 4; /* Hope the values REALLY don't matter */ 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = ((unsigned char *) lvcc->tx.buf.ptr) - 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char *) lvcc->tx.buf.start; 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((pos & ~0x0001FFF0) == 0, 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_tx_add_aal5_descriptor: bad pos (%d) before, vci=%d, " 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci, 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end); 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = (pos + len) & (lanai_buf_size(&lvcc->tx.buf) - 1); 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((pos & ~0x0001FFF0) == 0, 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_tx_add_aal5_descriptor: bad pos (%d) after, vci=%d, " 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci, 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end); 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr[-1] = 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_le32(DESCRIPTOR_MAGIC | DESCRIPTOR_AAL5 | 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((lvcc->tx.atmvcc->atm_options & ATM_ATMOPT_CLP) ? 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DESCRIPTOR_CLP : 0) | flags | pos >> 4); 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end) 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr = lvcc->tx.buf.start; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Add 32-bit AAL5 trailer and leave room for its CRC */ 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_tx_add_aal5_trailer(struct lanai_vcc *lvcc, 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len, int cpi, int uu) 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 8, 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_tx_add_aal5_trailer: bad ptr=%p\n", lvcc->tx.buf.ptr); 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr += 2; 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr[-2] = cpu_to_be32((uu << 24) | (cpi << 16) | len); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end) 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr = lvcc->tx.buf.start; 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_tx_memcpy(struct lanai_vcc *lvcc, 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *src, int n) 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *e; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int m; 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e = ((unsigned char *) lvcc->tx.buf.ptr) + n; 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = e - (unsigned char *) lvcc->tx.buf.end; 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m < 0) 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = 0; 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(lvcc->tx.buf.ptr, src, n - m); 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m != 0) { 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(lvcc->tx.buf.start, src + n - m, m); 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e = ((unsigned char *) lvcc->tx.buf.start) + m; 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr = (u32 *) e; 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_tx_memzero(struct lanai_vcc *lvcc, int n) 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *e; 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int m; 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n == 0) 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e = ((unsigned char *) lvcc->tx.buf.ptr) + n; 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = e - (unsigned char *) lvcc->tx.buf.end; 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m < 0) 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = 0; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(lvcc->tx.buf.ptr, 0, n - m); 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m != 0) { 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(lvcc->tx.buf.start, 0, m); 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds e = ((unsigned char *) lvcc->tx.buf.start) + m; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.ptr = (u32 *) e; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Update "butt" register to specify new WritePtr */ 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_endtx(struct lanai_dev *lanai, 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct lanai_vcc *lvcc) 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, ptr = ((unsigned char *) lvcc->tx.buf.ptr) - 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned char *) lvcc->tx.buf.start; 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((ptr & ~0x0001FFF0) == 0, 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "lanai_endtx: bad ptr (%d), vci=%d, start,ptr,end=%p,%p,%p\n", 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ptr, lvcc->vci, lvcc->tx.buf.start, lvcc->tx.buf.ptr, 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.buf.end); 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since the "butt register" is a shared resounce on the card we 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * serialize all accesses to it through this spinlock. This is 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mostly just paranoia sicne the register is rarely "busy" anyway 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but is needed for correctness. 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lanai->endtxlock); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We need to check if the "butt busy" bit is set before 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * updating the butt register. In theory this should 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * never happen because the ATM card is plenty fast at 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * updating the register. Still, we should make sure 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; reg_read(lanai, Status_Reg) & STATUS_BUTTBUSY; i++) { 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(i > 50)) { 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): butt register " 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "always busy!\n", lanai->number); 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(5); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before we tall the card to start work we need to be sure 100% of 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the info in the service buffer has been written before we tell 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the card about it 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wmb(); 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, (ptr << 12) | lvcc->vci, Butt_Reg); 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lanai->endtxlock); 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add one AAL5 PDU to lvcc's transmit buffer. Caller garauntees there's 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * space available. "pdusize" is the number of bytes the PDU will take 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_send_one_aal5(struct lanai_dev *lanai, 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc, struct sk_buff *skb, int pdusize) 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pad; 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(pdusize == aal5_size(skb->len), 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "lanai_send_one_aal5: wrong size packet (%d != %d)\n", 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdusize, aal5_size(skb->len)); 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_add_aal5_descriptor(lvcc, 0, pdusize); 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pad = pdusize - skb->len - 8; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(pad >= 0, "pad is negative (%d)\n", pad); 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(pad < 48, "pad is too big (%d)\n", pad); 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_memcpy(lvcc, skb->data, skb->len); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_memzero(lvcc, pad); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_add_aal5_trailer(lvcc, skb->len, 0, 0); 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_endtx(lanai, lvcc); 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_free_skb(lvcc->tx.atmvcc, skb); 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->tx.atmvcc->stats->tx); 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Try to fill the buffer - don't call unless there is backlog */ 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_tx_unqueue_aal5(struct lanai_dev *lanai, 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc, int endptr) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int space = vcc_tx_space(lvcc, endptr); 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(vcc_is_backlogged(lvcc), 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_tx_unqueue() called with empty backlog (vci=%d)\n", 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vci); 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (space >= 64) { 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = skb_dequeue(&lvcc->tx.backlog); 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto no_backlog; 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = aal5_size(skb->len); 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n + 16 > space) { 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No room for this packet - put it back on queue */ 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head(&lvcc->tx.backlog, skb); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_send_one_aal5(lanai, lvcc, skb, n); 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds space -= n + 16; 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!vcc_is_backlogged(lvcc)) { 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds no_backlog: 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __clear_bit(lvcc->vci, lanai->backlog_vccs); 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Given an skb that we want to transmit either send it now or queue */ 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_tx_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc, 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int space, n; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc_is_backlogged(lvcc)) /* Already backlogged */ 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto queue_it; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds space = vcc_tx_space(lvcc, 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr))); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = aal5_size(skb->len); 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(n + 16 >= 64, "vcc_tx_aal5: n too small (%d)\n", n); 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (space < n + 16) { /* No space for this PDU */ 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __set_bit(lvcc->vci, lanai->backlog_vccs); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds queue_it: 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_tail(&lvcc->tx.backlog, skb); 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_send_one_aal5(lanai, lvcc, skb, n); 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_tx_unqueue_aal0(struct lanai_dev *lanai, 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc, int endptr) 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ": vcc_tx_unqueue_aal0: not implemented\n"); 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_tx_aal0(struct lanai_dev *lanai, struct lanai_vcc *lvcc, 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb) 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL ": vcc_tx_aal0: not implemented\n"); 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remember to increment lvcc->tx.atmvcc->stats->tx */ 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_free_skb(lvcc->tx.atmvcc, skb); 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- VCC RX BUFFER UTILITIES: */ 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* unlike the _tx_ cousins, this doesn't update ptr */ 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_rx_memcpy(unsigned char *dest, 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct lanai_vcc *lvcc, int n) 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int m = ((const unsigned char *) lvcc->rx.buf.ptr) + n - 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((const unsigned char *) (lvcc->rx.buf.end)); 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (m < 0) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds m = 0; 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dest, lvcc->rx.buf.ptr, n - m); 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dest + n - m, lvcc->rx.buf.start, m); 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure that these copies don't get reordered */ 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Receive AAL5 data on a VCC with a particular endptr */ 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*const*/ u32 *x, *end = &lvcc->rx.buf.start[endptr * 4]; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n = ((unsigned long) end) - ((unsigned long) lvcc->rx.buf.ptr); 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n < 0) 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n += lanai_buf_size(&lvcc->rx.buf); 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(n >= 0 && n < lanai_buf_size(&lvcc->rx.buf) && !(n & 15), 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc_rx_aal5: n out of range (%d/%Zu)\n", 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n, lanai_buf_size(&lvcc->rx.buf)); 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Recover the second-to-last word to get true pdu length */ 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((x = &end[-2]) < lvcc->rx.buf.start) 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = &lvcc->rx.buf.end[-2]; 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Before we actually read from the buffer, make sure the memory 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * changes have arrived 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rmb(); 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = be32_to_cpup(x) & 0xffff; 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(n != aal5_size(size))) { 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure size matches padding */ 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL "(itf %d): Got bad AAL5 length " 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "on vci=%d - size=%d n=%d\n", 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc->dev->number, lvcc->vci, size, n); 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.rx_badlen++; 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = atm_alloc_charge(lvcc->rx.atmvcc, size, GFP_ATOMIC); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(skb == NULL)) { 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.rx_nomem++; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put(skb, size); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rx_memcpy(skb->data, lvcc, size); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SKB(skb)->vcc = lvcc->rx.atmvcc; 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do_gettimeofday(&skb->stamp); 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb); 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->rx.atmvcc->stats->rx); 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.buf.ptr = end; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, endptr, vcc_rxreadptr); 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void vcc_rx_aal0(struct lanai_dev *lanai) 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL ": vcc_rx_aal0: not implemented\n"); 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remember to get read_lock(&vcc_sklist_lock) while looking up VC */ 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remember to increment lvcc->rx.atmvcc->stats->rx */ 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- MANAGING HOST-BASED VCC TABLE: */ 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Decide whether to use vmalloc or get_zeroed_page for VCC table */ 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if (NUM_VCI * BITS_PER_LONG) <= PAGE_SIZE 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VCCTABLE_GETFREEPAGE 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit vcc_table_allocate(struct lanai_dev *lanai) 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef VCCTABLE_GETFREEPAGE 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK((lanai->num_vci) * sizeof(struct lanai_vcc *) <= PAGE_SIZE, 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc table > PAGE_SIZE!"); 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->vccs = (struct lanai_vcc **) get_zeroed_page(GFP_KERNEL); 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (lanai->vccs == NULL) ? -ENOMEM : 0; 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes = (lanai->num_vci) * sizeof(struct lanai_vcc *); 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->vccs = (struct lanai_vcc **) vmalloc(bytes); 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lanai->vccs == NULL)) 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(lanai->vccs, 0, bytes); 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void vcc_table_deallocate(const struct lanai_dev *lanai) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef VCCTABLE_GETFREEPAGE 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_page((unsigned long) lanai->vccs); 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vfree(lanai->vccs); 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Allocate a fresh lanai_vcc, with the appropriate things cleared */ 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline struct lanai_vcc *new_lanai_vcc(void) 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc; 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc = (struct lanai_vcc *) kmalloc(sizeof(*lvcc), GFP_KERNEL); 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (likely(lvcc != NULL)) { 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vbase = NULL; 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc = lvcc->tx.atmvcc = NULL; 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->nref = 0; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&lvcc->stats, 0, sizeof lvcc->stats); 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.buf.start = lvcc->tx.buf.start = NULL; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_queue_head_init(&lvcc->tx.backlog); 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.unqueue = NULL; 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vci = -1; 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lvcc; 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_get_sized_buffer(struct lanai_dev *lanai, 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_buffer *buf, int max_sdu, int multiplier, 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name) 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size; 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(max_sdu < 1)) 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_sdu = 1; 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_sdu = aal5_size(max_sdu); 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = (max_sdu + 16) * multiplier + 16; 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_allocate(buf, size, max_sdu + 32, lanai->pci); 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(buf->start == NULL)) 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lanai_buf_size(buf) < size)) 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING DEV_LABEL "(itf %d): wanted %d bytes " 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "for %s buffer, got only %Zu\n", lanai->number, size, 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name, lanai_buf_size(buf)); 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Allocated %Zu byte %s buffer\n", lanai_buf_size(buf), name); 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Setup a RX buffer for a currently unbound AAL5 vci */ 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int lanai_setup_rx_vci_aal5(struct lanai_dev *lanai, 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc, const struct atm_qos *qos) 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lanai_get_sized_buffer(lanai, &lvcc->rx.buf, 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, "RX"); 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Setup a TX buffer for a currently unbound AAL5 vci */ 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_setup_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc, 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct atm_qos *qos) 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_sdu, multiplier; 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->aal == ATM_AAL0) { 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.unqueue = vcc_tx_unqueue_aal0; 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_sdu = ATM_CELL_SIZE - 1; 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multiplier = AAL0_TX_MULTIPLIER; 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.unqueue = vcc_tx_unqueue_aal5; 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_sdu = qos->txtp.max_sdu; 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multiplier = AAL5_TX_MULTIPLIER; 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lanai_get_sized_buffer(lanai, &lvcc->tx.buf, max_sdu, 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds multiplier, "TX"); 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void host_vcc_bind(struct lanai_dev *lanai, 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc, vci_t vci) 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->vbase != NULL) 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; /* We already were bound in the other direction */ 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Binding vci %d\n", vci); 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->nbound++ == 0) { 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Coming out of powerdown\n"); 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 &= ~CONFIG1_POWERDOWN; 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write(lanai); 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vbase = cardvcc_addr(lanai, vci); 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->vccs[lvcc->vci = vci] = lvcc; 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void host_vcc_unbind(struct lanai_dev *lanai, 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc) 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->vbase == NULL) 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; /* This vcc was never bound */ 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Unbinding vci %d\n", lvcc->vci); 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->vbase = NULL; 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->vccs[lvcc->vci] = NULL; 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--lanai->nbound == 0) { 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Going into powerdown\n"); 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= CONFIG1_POWERDOWN; 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- RESET CARD: */ 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_reset(struct lanai_dev *lanai) 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_CRIT DEV_LABEL "(itf %d): *NOT* reseting - not " 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "implemented\n", lanai->number); 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO */ 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The following is just a hack until we write the real 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * resetter - at least ack whatever interrupt sent us 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, INT_ALL, IntAck_Reg); 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.card_reset++; 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- SERVICE LIST UTILITIES: */ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate service buffer and tell card about it 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit service_buffer_allocate(struct lanai_dev *lanai) 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 8, 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->pci); 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lanai->service.start == NULL)) 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("allocated service buffer at 0x%08lX, size %Zu(%d)\n", 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) lanai->service.start, 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_size(&lanai->service), 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_size_cardorder(&lanai->service)); 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear ServWrite register to be safe */ 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, 0, ServWrite_Reg); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ServiceStuff register contains size and address of buffer */ 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SSTUFF_SET_SIZE(lanai_buf_size_cardorder(&lanai->service)) | 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SSTUFF_SET_ADDR(lanai->service.dmaaddr), 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ServiceStuff_Reg); 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void service_buffer_deallocate(struct lanai_dev *lanai) 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_deallocate(&lanai->service, lanai->pci); 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bitfields in service list */ 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_TX (0x80000000) /* Was from transmission */ 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_TRASH (0x40000000) /* RXed PDU was trashed */ 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_CRCERR (0x20000000) /* RXed PDU had CRC error */ 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_CI (0x10000000) /* RXed PDU had CI set */ 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_CLP (0x08000000) /* RXed PDU had CLP set */ 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_STREAM (0x04000000) /* RX Stream mode */ 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_GET_VCI(x) (((x)>>16)&0x3FF) 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SERVICE_GET_END(x) ((x)&0x1FFF) 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Handle one thing from the service list - returns true if it marked a 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * VCC ready for xmit 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int handle_service(struct lanai_dev *lanai, u32 s) 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_t vci = SERVICE_GET_VCI(s); 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc; 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&vcc_sklist_lock); 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc = lanai->vccs[vci]; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc == NULL)) { 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("(itf %d) got service entry 0x%X for nonexistent " 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc %d\n", lanai->number, (unsigned int) s, vci); 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s & SERVICE_TX) 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_notx++; 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_norx++; 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s & SERVICE_TX) { /* segmentation interrupt */ 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc->tx.atmvcc == NULL)) { 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("(itf %d) got service entry 0x%X for non-TX " 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc %d\n", lanai->number, (unsigned int) s, vci); 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_notx++; 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __set_bit(vci, lanai->transmit_ready); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.endptr = SERVICE_GET_END(s); 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc->rx.atmvcc == NULL)) { 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("(itf %d) got service entry 0x%X for non-RX " 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc %d\n", lanai->number, (unsigned int) s, vci); 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_norx++; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc->rx.atmvcc->qos.aal != ATM_AAL5)) { 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 " 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "vcc %d\n", lanai->number, (unsigned int) s, vci); 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_rxnotaal5++; 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (likely(!(s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)))) { 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rx_aal5(lvcc, SERVICE_GET_END(s)); 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s & SERVICE_TRASH) { 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int bytes; 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("got trashed rx pdu on vci %d\n", vci); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_trash++; 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes = (SERVICE_GET_END(s) * 16) - 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (((unsigned long) lvcc->rx.buf.ptr) - 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((unsigned long) lvcc->rx.buf.start)) + 47; 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bytes < 0) 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes += lanai_buf_size(&lvcc->rx.buf); 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.ovfl_trash += (bytes / 48); 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (s & SERVICE_STREAM) { 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_stream++; 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream " 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PDU on VCI %d!\n", lanai->number, vci); 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_reset(lanai); 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("got rx crc error on vci %d\n", vci); 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_rxcrc++; 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4]; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr); 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Try transmitting on all VCIs that we marked ready to serve */ 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iter_transmit(struct lanai_dev *lanai, vci_t vci) 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc = lanai->vccs[vci]; 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc_is_backlogged(lvcc)) 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.unqueue(lanai, lvcc, lvcc->tx.endptr); 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Run service queue -- called from interrupt context or with 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts otherwise disabled and with the lanai->servicelock 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lock held 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void run_service(struct lanai_dev *lanai) 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ntx = 0; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 wreg = reg_read(lanai, ServWrite_Reg); 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u32 *end = lanai->service.start + wreg; 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (lanai->service.ptr != end) { 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ntx += handle_service(lanai, 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds le32_to_cpup(lanai->service.ptr++)); 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->service.ptr >= lanai->service.end) 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->service.ptr = lanai->service.start; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, wreg, ServRead_Reg); 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ntx != 0) { 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&vcc_sklist_lock); 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_bitfield_iterate(lanai, lanai->transmit_ready, 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iter_transmit); 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bitmap_zero(lanai->transmit_ready, NUM_VCI); 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- GATHER STATISTICS: */ 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void get_statistics(struct lanai_dev *lanai) 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 statreg = reg_read(lanai, Statistics_Reg); 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.atm_ovfl += STATS_GET_FIFO_OVFL(statreg); 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.hec_err += STATS_GET_HEC_ERR(statreg); 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.vci_trash += STATS_GET_BAD_VCI(statreg); 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.ovfl_trash += STATS_GET_BUF_OVFL(statreg); 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- POLLING TIMER: */ 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef DEBUG_RW 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Try to undequeue 1 backlogged vcc */ 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void iter_dequeue(struct lanai_dev *lanai, vci_t vci) 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc = lanai->vccs[vci]; 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int endptr; 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc == NULL || lvcc->tx.atmvcc == NULL || 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !vcc_is_backlogged(lvcc)) { 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __clear_bit(vci, lanai->backlog_vccs); 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds endptr = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.unqueue(lanai, lvcc, endptr); 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* !DEBUG_RW */ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_timed_poll(unsigned long arg) 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) arg; 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef DEBUG_RW 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->conf1 & CONFIG1_POWERDOWN) 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* USE_POWERDOWN */ 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we can grab the spinlock, check if any services need to be run */ 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (spin_trylock(&lanai->servicelock)) { 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds run_service(lanai); 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lanai->servicelock); 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ...and see if any backlogged VCs can make progress */ 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unfortunately linux has no read_trylock() currently */ 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&vcc_sklist_lock); 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci_bitfield_iterate(lanai, lanai->backlog_vccs, iter_dequeue); 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_statistics(lanai); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* !DEBUG_RW */ 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&lanai->timer, jiffies + LANAI_POLL_PERIOD); 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_timed_poll_start(struct lanai_dev *lanai) 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&lanai->timer); 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->timer.expires = jiffies + LANAI_POLL_PERIOD; 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->timer.data = (unsigned long) lanai; 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->timer.function = lanai_timed_poll; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&lanai->timer); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_timed_poll_stop(struct lanai_dev *lanai) 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&lanai->timer); 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- INTERRUPT SERVICE: */ 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_int_1(struct lanai_dev *lanai, u32 reason) 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ack = 0; 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason & INT_SERVICE) { 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack = INT_SERVICE; 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lanai->servicelock); 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds run_service(lanai); 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lanai->servicelock); 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason & (INT_AAL0_STR | INT_AAL0)) { 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack |= reason & (INT_AAL0_STR | INT_AAL0); 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_rx_aal0(lanai); 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The rest of the interrupts are pretty rare */ 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ack == reason) 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto done; 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason & INT_STATS) { 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reason &= ~INT_STATS; /* No need to ack */ 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_statistics(lanai); 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason & INT_STATUS) { 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack |= reason & INT_STATUS; 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_check_status(lanai); 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(reason & INT_DMASHUT)) { 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): driver error - DMA " 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "shutdown, reason=0x%08X, address=0x%08X\n", 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number, (unsigned int) (reason & INT_DMASHUT), 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) reg_read(lanai, DMA_Addr_Reg)); 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason & INT_TABORTBM) { 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_reset(lanai); 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack |= (reason & INT_DMASHUT); 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): re-enabling DMA\n", 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number); 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.dma_reenable++; 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_check(lanai, 0); 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(reason & INT_TABORTSENT)) { 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack |= (reason & INT_TABORTSENT); 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): sent PCI target abort\n", 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number); 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_check(lanai, 0); 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(reason & INT_SEGSHUT)) { 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): driver error - " 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "segmentation shutdown, reason=0x%08X\n", lanai->number, 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) (reason & INT_SEGSHUT)); 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_reset(lanai); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(reason & (INT_PING | INT_WAKE))) { 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): driver error - " 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "unexpected interrupt 0x%08X, resetting\n", 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number, 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) (reason & (INT_PING | INT_WAKE))); 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_reset(lanai); 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(ack != reason)) { 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("unacked ints: 0x%08X\n", 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) (reason & ~ack)); 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ack = reason; 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done: 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ack != 0) 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, ack, IntAck_Reg); 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t lanai_int(int irq, void *devid, struct pt_regs *regs) 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) devid; 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 reason; 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) irq; (void) regs; /* unused variables */ 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we're powered down we shouldn't be generating any interrupts - 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so assume that this is a shared interrupt line and it's for someone 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * else 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lanai->conf1 & CONFIG1_POWERDOWN)) 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reason = intr_pending(lanai); 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason == 0) 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; /* Must be for someone else */ 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(reason == 0xFFFFFFFF)) 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* Maybe we've been unplugged? */ 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_int_1(lanai, reason); 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reason = intr_pending(lanai); 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (reason != 0); 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO - it would be nice if we could use the "delayed interrupt" system 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to some advantage 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- CHECK BOARD ID/REV: */ 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The board id and revision are stored both in the reset register and 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the PCI configuration space - the documentation says to check 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each of them. If revp!=NULL we store the revision there 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_board_id_and_rev(const char *name, u32 val, int *revp) 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("%s says board_id=%d, board_rev=%d\n", name, 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) RESET_GET_BOARD_ID(val), 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) RESET_GET_BOARD_REV(val)); 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (RESET_GET_BOARD_ID(val) != BOARD_ID_LANAI256) { 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL ": Found %s board-id %d -- not a " 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Lanai 25.6\n", name, (int) RESET_GET_BOARD_ID(val)); 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (revp != NULL) 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *revp = RESET_GET_BOARD_REV(val); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- PCI INITIALIZATION/SHUTDOWN: */ 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit lanai_pci_start(struct lanai_dev *lanai) 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pci = lanai->pci; 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 w; 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_enable_device(pci) != 0) { 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't enable " 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PCI device", lanai->number); 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_set_master(pci); 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_set_dma_mask(pci, DMA_32BIT_MASK) != 0) { 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING DEV_LABEL 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(itf %d): No suitable DMA available.\n", lanai->number); 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_set_consistent_dma_mask(pci, 0xFFFFFFFF) != 0) { 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING DEV_LABEL 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(itf %d): No suitable DMA available.\n", lanai->number); 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Get the pci revision byte */ 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = pci_read_config_byte(pci, PCI_REVISION_ID, 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &lanai->pci_revision); 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != PCIBIOS_SUCCESSFUL) { 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't read " 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PCI_REVISION_ID: %d\n", lanai->number, result); 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w); 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != PCIBIOS_SUCCESSFUL) { 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't read " 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PCI_SUBSYSTEM_ID: %d\n", lanai->number, result); 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = check_board_id_and_rev("PCI", w, NULL); 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != 0) 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set latency timer to zero as per lanai docs */ 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0); 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != PCIBIOS_SUCCESSFUL) { 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL "(itf %d): can't write " 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "PCI_LATENCY_TIMER: %d\n", lanai->number, result); 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_check(lanai, 1); 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_check(lanai, 0); 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- VPI/VCI ALLOCATION: */ 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We _can_ use VCI==0 for normal traffic, but only for UBR (or we'll 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get a CBRZERO interrupt), and we can use it only if noone is receiving 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AAL0 traffic (since they will use the same queue) - according to the 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * docs we shouldn't even use it for AAL0 traffic 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int vci0_is_ok(struct lanai_dev *lanai, 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct atm_qos *qos) 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->txtp.traffic_class == ATM_CBR || qos->aal == ATM_AAL0) 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->rxtp.traffic_class != ATM_NONE) { 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->naal0 != 0) 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf2 |= CONFIG2_VCI0_NORMAL; 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write_if_powerup(lanai); 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* return true if vci is currently unused, or if requested qos is 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * compatible 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int vci_is_ok(struct lanai_dev *lanai, vci_t vci, 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct atm_vcc *atmvcc) 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct atm_qos *qos = &atmvcc->qos; 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct lanai_vcc *lvcc = lanai->vccs[vci]; 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vci == 0 && !vci0_is_ok(lanai, qos)) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc != NULL)) { 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->rxtp.traffic_class != ATM_NONE && 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc != NULL && lvcc->rx.atmvcc != atmvcc) 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->txtp.traffic_class != ATM_NONE && 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc != NULL && lvcc->tx.atmvcc != atmvcc) 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->txtp.traffic_class == ATM_CBR && 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->cbrvcc != NULL && lanai->cbrvcc != atmvcc) 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qos->aal == ATM_AAL0 && lanai->naal0 == 0 && 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qos->rxtp.traffic_class != ATM_NONE) { 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct lanai_vcc *vci0 = lanai->vccs[0]; 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vci0 != NULL && vci0->rx.atmvcc != NULL) 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf2 &= ~CONFIG2_VCI0_NORMAL; 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write_if_powerup(lanai); 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_normalize_ci(struct lanai_dev *lanai, 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct atm_vcc *atmvcc, short *vpip, vci_t *vcip) 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*vpip) { 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_VPI_ANY: 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vpip = 0; 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FALLTHROUGH */ 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EADDRINUSE; 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (*vcip) { 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_VCI_ANY: 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (*vcip = ATM_NOT_RSV_VCI; *vcip < lanai->num_vci; 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*vcip)++) 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vci_is_ok(lanai, *vcip, atmvcc)) 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EADDRINUSE; 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*vcip >= lanai->num_vci || *vcip < 0 || 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !vci_is_ok(lanai, *vcip, atmvcc)) 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EADDRINUSE; 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- MANAGE CBR: */ 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * CBR ICG is stored as a fixed-point number with 4 fractional bits. 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that storing a number greater than 2046.0 will result in 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * incorrect shaping 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CBRICG_FRAC_BITS (4) 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CBRICG_MAX (2046 << CBRICG_FRAC_BITS) 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ICG is related to PCR with the formula PCR = MAXPCR / (ICG + 1) 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where MAXPCR is (according to the docs) 25600000/(54*8), 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which is equal to (3125<<9)/27. 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Solving for ICG, we get: 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ICG = MAXPCR/PCR - 1 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ICG = (3125<<9)/(27*PCR) - 1 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ICG = ((3125<<9) - (27*PCR)) / (27*PCR) 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The end result is supposed to be a fixed-point number with FRAC_BITS 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bits of a fractional part, so we keep everything in the numerator 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shifted by that much as we compute 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pcr_to_cbricg(/*const*/ struct atm_qos *qos) 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rounddown = 0; /* 1 = Round PCR down, i.e. round ICG _up_ */ 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x, icg, pcr = atm_pcr_goal(&qos->txtp); 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pcr == 0) /* Use maximum bandwidth */ 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pcr < 0) { 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rounddown = 1; 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = -pcr; 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = pcr * 27; 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icg = (3125 << (9 + CBRICG_FRAC_BITS)) - (x << CBRICG_FRAC_BITS); 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rounddown) 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icg += x - 1; 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icg /= x; 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (icg > CBRICG_MAX) 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds icg = CBRICG_MAX; 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("pcr_to_cbricg: pcr=%d rounddown=%c icg=%d\n", 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr, rounddown ? 'Y' : 'N', icg); 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return icg; 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_cbr_setup(struct lanai_dev *lanai) 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, pcr_to_cbricg(&lanai->cbrvcc->qos), CBR_ICG_Reg); 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, lanai->cbrvcc->vci, CBR_PTR_Reg); 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf2 |= CONFIG2_CBR_ENABLE; 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write(lanai); 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void lanai_cbr_shutdown(struct lanai_dev *lanai) 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf2 &= ~CONFIG2_CBR_ENABLE; 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write(lanai); 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- OPERATIONS: */ 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* setup a newly detected device */ 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit lanai_dev_open(struct atm_dev *atmdev) 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long raw_base; 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("In lanai_dev_open()\n"); 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Basic device fields */ 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number = atmdev->number; 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->num_vci = NUM_VCI; 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bitmap_zero(lanai->backlog_vccs, NUM_VCI); 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bitmap_zero(lanai->transmit_ready, NUM_VCI); 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->naal0 = 0; 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->nbound = 0; 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->cbrvcc = NULL; 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&lanai->stats, 0, sizeof lanai->stats); 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&lanai->endtxlock); 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&lanai->servicelock); 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->ci_range.vpi_bits = 0; 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->ci_range.vci_bits = 0; 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1 << atmdev->ci_range.vci_bits < lanai->num_vci) 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->ci_range.vci_bits++; 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->link_rate = ATM_25_PCR; 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.2: PCI initialization */ 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = lanai_pci_start(lanai)) != 0) 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds raw_base = lanai->pci->resource[0].start; 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE); 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->base == NULL) { 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n"); 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_pci; 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.3: Reset lanai and PHY */ 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_board(lanai); 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 = reg_read(lanai, Config1_Reg); 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 &= ~(CONFIG1_GPOUT1 | CONFIG1_POWERDOWN | 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CONFIG1_MASK_LEDMODE); 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= CONFIG1_SET_LEDMODE(LEDMODE_NOT_SOOL); 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, lanai->conf1 | CONFIG1_GPOUT1, Config1_Reg); 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3.4: Turn on endian mode for big-endian hardware 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't actually want to do this - the actual bit fields 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the endian register are not documented anywhere. 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Instead we do the bit-flipping ourselves on big-endian 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hardware. 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3.5: get the board ID/rev by reading the reset register 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = check_board_id_and_rev("register", 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_read(lanai, Reset_Reg), &lanai->board_rev); 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != 0) 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_unmap; 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.6: read EEPROM */ 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = eeprom_read(lanai)) != 0) 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_unmap; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = eeprom_validate(lanai)) != 0) 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_unmap; 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.7: re-reset PHY, do loopback tests, setup PHY */ 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, lanai->conf1 | CONFIG1_GPOUT1, Config1_Reg); 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000); 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* TODO - loopback tests */ 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= (CONFIG1_GPOUT2 | CONFIG1_GPOUT3 | CONFIG1_DMA_ENABLE); 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.8/3.9: test and initialize card SRAM */ 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = sram_test_and_clear(lanai)) != 0) 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_unmap; 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.10: initialize lanai registers */ 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= CONFIG1_DMA_ENABLE; 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = service_buffer_allocate(lanai)) != 0) 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_unmap; 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = vcc_table_allocate(lanai)) != 0) 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_service; 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf2 = (lanai->num_vci >= 512 ? CONFIG2_HOWMANY : 0) | 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CONFIG2_HEC_DROP | /* ??? */ CONFIG2_PTI7_MODE; 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf2_write(lanai); 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, TX_FIFO_DEPTH, TxDepth_Reg); 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg_write(lanai, 0, CBR_ICG_Reg); /* CBR defaults to no limit */ 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((result = request_irq(lanai->pci->irq, lanai_int, SA_SHIRQ, 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEV_LABEL, lanai)) != 0) { 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL ": can't allocate interrupt\n"); 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error_vcctable; 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mb(); /* Make sure that all that made it */ 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr_enable(lanai, INT_ALL & ~(INT_PING | INT_WAKE)); 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3.11: initialize loop mode (i.e. turn looping off) */ 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 = (lanai->conf1 & ~CONFIG1_MASK_LOOPMODE) | 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CONFIG1_SET_LOOPMODE(LOOPMODE_NORMAL) | 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CONFIG1_GPOUT2 | CONFIG1_GPOUT3; 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->status = reg_read(lanai, Status_Reg); 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We're now done initializing this card */ 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= CONFIG1_POWERDOWN; 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(atmdev->esi, eeprom_mac(lanai), ESI_LEN); 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_timed_poll_start(lanai); 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=0x%lx, irq=%u " 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(%02X-%02X-%02X-%02X-%02X-%02X)\n", lanai->number, 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) lanai->pci_revision, (unsigned long) lanai->base, 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->pci->irq, 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->esi[0], atmdev->esi[1], atmdev->esi[2], 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->esi[3], atmdev->esi[4], atmdev->esi[5]); 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_NOTICE DEV_LABEL "(itf %d): LANAI%s, serialno=%u(0x%X), " 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "board_rev=%d\n", lanai->number, 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->type==lanai2 ? "2" : "HB", (unsigned int) lanai->serialno, 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) lanai->serialno, lanai->board_rev); 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error_vcctable: 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_table_deallocate(lanai); 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error_service: 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds service_buffer_deallocate(lanai); 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error_unmap: 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_board(lanai); 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 = reg_read(lanai, Config1_Reg) | CONFIG1_POWERDOWN; 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(lanai->base); 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error_pci: 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(lanai->pci); 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error: 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called when device is being shutdown, and all vcc's are gone - higher 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * levels will deallocate the atm device for us 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_dev_close(struct atm_dev *atmdev) 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO DEV_LABEL "(itf %d): shutting down interface\n", 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->number); 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_timed_poll_stop(lanai); 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 = reg_read(lanai, Config1_Reg) & ~CONFIG1_POWERDOWN; 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds intr_disable(lanai, INT_ALL); 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(lanai->pci->irq, lanai); 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_board(lanai); 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 |= CONFIG1_POWERDOWN; 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(lanai->pci); 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_table_deallocate(lanai); 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds service_buffer_deallocate(lanai); 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(lanai->base); 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(lanai); 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* close a vcc */ 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lanai_close(struct atm_vcc *atmvcc) 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc = (struct lanai_vcc *) atmvcc->dev_data; 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmvcc->dev->dev_data; 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc == NULL) 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(ATM_VF_READY, &atmvcc->flags); 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(ATM_VF_PARTIAL, &atmvcc->flags); 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->rx.atmvcc == atmvcc) { 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_shutdown_rx_vci(lvcc); 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.aal == ATM_AAL0) { 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--lanai->naal0 <= 0) 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aal0_buffer_free(lanai); 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_deallocate(&lvcc->rx.buf, lanai->pci); 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc = NULL; 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->tx.atmvcc == atmvcc) { 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc == lanai->cbrvcc) { 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->vbase != NULL) 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_cbr_shutdown(lanai); 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->cbrvcc = NULL; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_shutdown_tx_vci(lanai, lvcc); 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_deallocate(&lvcc->tx.buf, lanai->pci); 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc = NULL; 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (--lvcc->nref == 0) { 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_vcc_unbind(lanai, lvcc); 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(lvcc); 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmvcc->dev_data = NULL; 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(ATM_VF_ADDR, &atmvcc->flags); 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* open a vcc on the card to vpi/vci */ 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_open(struct atm_vcc *atmvcc) 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai; 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc; 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int vci = atmvcc->vci; 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short vpi = atmvcc->vpi; 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we don't support partial open - it's not really useful anyway */ 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((test_bit(ATM_VF_PARTIAL, &atmvcc->flags)) || 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (vpi == ATM_VPI_UNSPEC) || (vci == ATM_VCI_UNSPEC)) 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai = (struct lanai_dev *) atmvcc->dev->dev_data; 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = lanai_normalize_ci(lanai, atmvcc, &vpi, &vci); 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(result != 0)) 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(ATM_VF_ADDR, &atmvcc->flags); 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.aal != ATM_AAL0 && atmvcc->qos.aal != ATM_AAL5) 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n", lanai->number, 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) vpi, vci); 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc = lanai->vccs[vci]; 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc == NULL) { 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc = new_lanai_vcc(); 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc == NULL)) 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmvcc->dev_data = lvcc; 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->nref++; 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.rxtp.traffic_class != ATM_NONE) { 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(lvcc->rx.atmvcc == NULL, "rx.atmvcc!=NULL, vci=%d\n", 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci); 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.aal == ATM_AAL0) { 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->naal0 == 0) 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = aal0_buffer_allocate(lanai); 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = lanai_setup_rx_vci_aal5( 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai, lvcc, &atmvcc->qos); 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(result != 0)) 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc = atmvcc; 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.rx_nomem = 0; 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.rx_badlen = 0; 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_trash = 0; 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_stream = 0; 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_rxcrc = 0; 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.aal == ATM_AAL0) 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->naal0++; 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.txtp.traffic_class != ATM_NONE) { 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(lvcc->tx.atmvcc == NULL, "tx.atmvcc!=NULL, vci=%d\n", 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vci); 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = lanai_setup_tx_vci(lanai, lvcc, &atmvcc->qos); 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(result != 0)) 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc = atmvcc; 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc->qos.txtp.traffic_class == ATM_CBR) { 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds APRINTK(lanai->cbrvcc == NULL, 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cbrvcc!=NULL, vci=%d\n", vci); 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->cbrvcc = atmvcc; 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_vcc_bind(lanai, lvcc, vci); 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure everything made it to RAM before we tell the card about 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the VCC 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wmb(); 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc == lvcc->rx.atmvcc) 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_vcc_start_rx(lvcc); 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmvcc == lvcc->tx.atmvcc) { 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_vcc_start_tx(lvcc); 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai->cbrvcc == atmvcc) 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_cbr_setup(lanai); 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(ATM_VF_READY, &atmvcc->flags); 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_free: 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_close(atmvcc); 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ioctl operations for card */ 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NOTE: these are all DEBUGGING ONLY currently */ 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_ioctl(struct atm_dev *atmdev, unsigned int cmd, void __user *arg) 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(cmd) { 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2106275: 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shutdown_atm_dev(atmdev); 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2200000: { 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lanai->servicelock, flags); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds run_service(lanai); 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lanai->servicelock, flags); 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; } 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2200002: 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_statistics(lanai); 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2200003: { 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i <= 0x5C ; i += 4) { 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i==0x48) /* Write-only butt reg */ 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_CRIT DEV_LABEL " 0x%02X: " 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "0x%08X\n", i, 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) readl(lanai->base + i)); 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); mb(); 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcistatus_check(lanai, 0); 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); mb(); 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; } 24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2200004: { 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 b; 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 w; 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dw; 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pci = lanai->pci; 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_word(pci, PCI_VENDOR_ID, &w); 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("vendor = 0x%X\n", (unsigned int) w); 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_word(pci, PCI_DEVICE_ID, &w); 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("device = 0x%X\n", (unsigned int) w); 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_word(pci, PCI_COMMAND, &w); 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("command = 0x%X\n", (unsigned int) w); 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_word(pci, PCI_STATUS, &w); 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("status = 0x%X\n", (unsigned int) w); 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_dword(pci, 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_CLASS_REVISION, &dw); 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("class/revision = 0x%X\n", (unsigned int) dw); 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_CACHE_LINE_SIZE, &b); 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("cache line size = 0x%X\n", (unsigned int) b); 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, PCI_LATENCY_TIMER, &b); 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("latency = %d (0x%X)\n", 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) b, (unsigned int) b); 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, PCI_HEADER_TYPE, &b); 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("header type = 0x%X\n", (unsigned int) b); 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, PCI_BIST, &b); 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("bist = 0x%X\n", (unsigned int) b); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* skipping a few here */ 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_INTERRUPT_LINE, &b); 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("pci_int_line = 0x%X\n", (unsigned int) b); 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_INTERRUPT_PIN, &b); 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("pci_int_pin = 0x%X\n", (unsigned int) b); 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, PCI_MIN_GNT, &b); 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("min_gnt = 0x%X\n", (unsigned int) b); 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) pci_read_config_byte(pci, PCI_MAX_LAT, &b); 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("max_lat = 0x%X\n", (unsigned int) b); } 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef USE_POWERDOWN 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2200005: 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("Coming out of powerdown\n"); 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->conf1 &= ~CONFIG1_POWERDOWN; 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds conf1_write(lanai); 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -ENOIOCTLCMD; 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else /* !0 */ 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define lanai_ioctl NULL 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* 0 */ 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_send(struct atm_vcc *atmvcc, struct sk_buff *skb) 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc = (struct lanai_vcc *) atmvcc->dev_data; 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmvcc->dev->dev_data; 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lvcc == NULL || lvcc->vbase == NULL || 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc != atmvcc)) 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto einval; 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(skb == NULL)) { 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("lanai_send: skb==NULL for vci=%d\n", atmvcc->vci); 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto einval; 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(lanai == NULL)) { 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("lanai_send: lanai==NULL for vci=%d\n", atmvcc->vci); 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto einval; 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SKB(skb)->vcc = atmvcc; 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (atmvcc->qos.aal) { 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_AAL5: 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock_irqsave(&vcc_sklist_lock, flags); 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_aal5(lanai, lvcc, skb); 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock_irqrestore(&vcc_sklist_lock, flags); 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_AAL0: 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unlikely(skb->len != ATM_CELL_SIZE-1)) 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto einval; 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NOTE - this next line is technically invalid - we haven't unshared skb */ 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_be32s((u32 *) skb->data); 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock_irqsave(&vcc_sklist_lock, flags); 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_tx_aal0(lanai, lvcc, skb); 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock_irqrestore(&vcc_sklist_lock, flags); 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("lanai_send: bad aal=%d on vci=%d\n", (int) atmvcc->qos.aal, 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmvcc->vci); 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds einval: 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_free_skb(atmvcc, skb); 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_change_qos(struct atm_vcc *atmvcc, 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*const*/ struct atm_qos *qos, int flags) 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; /* TODO: need to write this */ 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef CONFIG_PROC_FS 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define lanai_proc_read NULL 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds loff_t left = *pos; 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_vcc *lvcc; 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, DEV_LABEL "(itf %d): chip=LANAI%s, " 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "serial=%u, magic=0x%08X, num_vci=%d\n", 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->number, lanai->type==lanai2 ? "2" : "HB", 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) lanai->serialno, 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned int) lanai->magicno, lanai->num_vci); 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "revision: board=%d, pci_if=%d\n", 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->board_rev, (int) lanai->pci_revision); 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "EEPROM ESI: " 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "%02X:%02X:%02X:%02X:%02X:%02X\n", 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 0], 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 1], 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 2], 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 3], 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 4], 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->eeprom[EEPROM_MAC + 5]); 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "status: SOOL=%d, LOCD=%d, LED=%d, " 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "GPIN=%d\n", (lanai->status & STATUS_SOOL) ? 1 : 0, 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lanai->status & STATUS_LOCD) ? 1 : 0, 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lanai->status & STATUS_LED) ? 1 : 0, 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lanai->status & STATUS_GPIN) ? 1 : 0); 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "global buffer sizes: service=%Zu, " 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "aal0_rx=%Zu\n", lanai_buf_size(&lanai->service), 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->naal0 ? lanai_buf_size(&lanai->aal0buf) : 0); 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) { 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds get_statistics(lanai); 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "cells in error: overflow=%u, " 26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "closed_vci=%u, bad_HEC=%u, rx_fifo=%u\n", 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.ovfl_trash, lanai->stats.vci_trash, 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.hec_err, lanai->stats.atm_ovfl); 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "PCI errors: parity_detect=%u, " 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "master_abort=%u, master_target_abort=%u,\n", 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.pcierr_parity_detect, 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.pcierr_serr_set, 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.pcierr_m_target_abort); 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, " slave_target_abort=%u, " 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "master_parity=%u\n", lanai->stats.pcierr_s_target_abort, 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.pcierr_master_parity); 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, " no_tx=%u, " 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "no_rx=%u, bad_rx_aal=%u\n", lanai->stats.service_norx, 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_notx, 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.service_rxnotaal5); 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left-- == 0) 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(page, "resets: dma=%u, card=%u\n", 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->stats.dma_reenable, lanai->stats.card_reset); 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* At this point, "left" should be the VCI we're looking for */ 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_lock(&vcc_sklist_lock); 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (; ; left++) { 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (left >= NUM_VCI) { 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = 0; 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((lvcc = lanai->vccs[left]) != NULL) 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*pos)++; 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Note that we re-use "left" here since we're done with it */ 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left = sprintf(page, "VCI %4d: nref=%d, rx_nomem=%u", (vci_t) left, 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->nref, lvcc->stats.rx_nomem); 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->rx.atmvcc != NULL) { 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left += sprintf(&page[left], ",\n rx_AAL=%d", 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->rx.atmvcc->qos.aal == ATM_AAL5 ? 5 : 0); 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left += sprintf(&page[left], ", rx_buf_size=%Zu, " 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "rx_bad_len=%u,\n rx_service_trash=%u, " 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "rx_service_stream=%u, rx_bad_crc=%u", 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_size(&lvcc->rx.buf), 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.rx_badlen, 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_trash, 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_stream, 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->stats.x.aal5.service_rxcrc); 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lvcc->tx.atmvcc != NULL) 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds left += sprintf(&page[left], ",\n tx_AAL=%d, " 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "tx_buf_size=%Zu, tx_qos=%cBR, tx_backlogged=%c", 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc->qos.aal == ATM_AAL5 ? 5 : 0, 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai_buf_size(&lvcc->tx.buf), 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lvcc->tx.atmvcc == lanai->cbrvcc ? 'C' : 'U', 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc_is_backlogged(lvcc) ? 'Y' : 'N'); 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page[left++] = '\n'; 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page[left] = '\0'; 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read_unlock(&vcc_sklist_lock); 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return left; 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PROC_FS */ 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* -------------------- HOOKS: */ 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct atmdev_ops ops = { 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dev_close = lanai_dev_close, 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = lanai_open, 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = lanai_close, 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ioctl = lanai_ioctl, 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .getsockopt = NULL, 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .setsockopt = NULL, 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send = lanai_send, 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .phy_put = NULL, 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .phy_get = NULL, 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .change_qos = lanai_change_qos, 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_read = lanai_proc_read, 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialize one probed card */ 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit lanai_init_one(struct pci_dev *pci, 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct pci_device_id *ident) 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lanai_dev *lanai; 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_dev *atmdev; 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai = (struct lanai_dev *) kmalloc(sizeof(*lanai), GFP_KERNEL); 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lanai == NULL) { 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ": couldn't allocate dev_data structure!\n"); 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev = atm_dev_register(DEV_LABEL, &ops, -1, NULL); 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atmdev == NULL) { 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ": couldn't register atm device!\n"); 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(lanai); 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atmdev->dev_data = lanai; 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->pci = pci; 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lanai->type = (enum lanai_type) ident->device; 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = lanai_dev_open(atmdev); 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result != 0) { 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("lanai_start() failed, err=%d\n", -result); 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atm_dev_deregister(atmdev); 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(lanai); 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id lanai_pci_tbl[] = { 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2, 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB, 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, } /* terminal entry */ 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, lanai_pci_tbl); 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver lanai_driver = { 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = DEV_LABEL, 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = lanai_pci_tbl, 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = lanai_init_one, 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init lanai_module_init(void) 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int x; 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = pci_register_driver(&lanai_driver); 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x != 0) 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR DEV_LABEL ": no adapter found\n"); 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x; 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit lanai_module_exit(void) 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We'll only get called when all the interfaces are already 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gone, so there isn't much to do 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK("cleanup_module()\n"); 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(lanai_module_init); 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(lanai_module_exit); 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>"); 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Efficient Networks Speedstream 3010 driver"); 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2771