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