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