11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Madge Horizon ATM Adapter driver. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright (C) 1995-1999 Madge Networks Ltd. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is free software; you can redistribute it and/or modify 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it under the terms of the GNU General Public License as published by 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the Free Software Foundation; either version 2 of the License, or 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (at your option) any later version. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is distributed in the hope that it will be useful, 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GNU General Public License for more details. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You should have received a copy of the GNU General Public License 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds along with this program; if not, write to the Free Software 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds system and in the file COPYING in the Linux kernel source. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IMPORTANT NOTE: Madge Networks no longer makes the adapters 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds supported by this driver and makes no commitment to maintain it. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atm.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atmdev.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sonet.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/time.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/uio.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 41a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/wait.h> 445a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 4860063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/string.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "horizon.h" 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define maintainer_string "Giuliano Procida at Madge Networks <gprocida@madge.com>" 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define description_string "Madge ATM Horizon [Ultra] driver" 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define version_string "1.2.1" 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void __init show_version (void) { 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%s version %s\n", description_string, version_string); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CREDITS 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Driver and documentation by: 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Chris Aston Madge Networks 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Giuliano Procida Madge Networks 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Simon Benham Madge Networks 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Simon Johnson Madge Networks 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Various Others Madge Networks 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Some inspiration taken from other drivers by: 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Alexandru Cucos UTBv 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Kari Mettinen University of Helsinki 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Werner Almesberger EPFL LRC 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Theory of Operation 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I Hardware, detection, initialisation and shutdown. 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. Supported Hardware 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver should handle all variants of the PCI Madge ATM adapters 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with the Horizon chipset. These are all PCI cards supporting PIO, BM 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA and a form of MMIO (registers only, not internal RAM). 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The driver is only known to work with SONET and UTP Horizon Ultra 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cards at 155Mb/s. However, code is in place to deal with both the 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds original Horizon and 25Mb/s operation. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds There are two revisions of the Horizon ASIC: the original and the 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Ultra. Details of hardware bugs are in section III. 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The ASIC version can be distinguished by chip markings but is NOT 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds indicated by the PCI revision (all adapters seem to have PCI rev 1). 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I believe that: 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Horizon => Collage 25 PCI Adapter (UTP and STP) 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Horizon Ultra => Collage 155 PCI Client (UTP or SONET) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Ambassador x => Collage 155 PCI Server (completely different) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Horizon (25Mb/s) is fitted with UTP and STP connectors. It seems to 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds have a Madge B154 plus glue logic serializer. I have also found a 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds really ancient version of this with slightly different glue. It 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds comes with the revision 0 (140-025-01) ASIC. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Horizon Ultra (155Mb/s) is fitted with either a Pulse Medialink 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds output (UTP) or an HP HFBR 5205 output (SONET). It has either 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Madge's SAMBA framer or a SUNI-lite device (early versions). It 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds comes with the revision 1 (140-027-01) ASIC. 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. Detection 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds All Horizon-based cards present with the same PCI Vendor and Device 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IDs. The standard Linux 2.2 PCI API is used to locate any cards and 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to enable bus-mastering (with appropriate latency). 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_LAYER_STATUS in the control register distinguishes between the 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds two possible physical layers (25 and 155). It is not clear whether 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the 155 cards can also operate at 25Mbps. We rely on the fact that a 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card operates at 155 if and only if it has the newer Horizon Ultra 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ASIC. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For 155 cards the two possible framers are probed for and then set 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up for loop-timing. 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3. Initialisation 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The card is reset and then put into a known state. The physical 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds layer is configured for normal operation at the appropriate speed; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in the case of the 155 cards, the framer is initialised with 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds line-based timing; the internal RAM is zeroed and the allocation of 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffers for RX and TX is made; the Burnt In Address is read and 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds copied to the ATM ESI; various policy settings for RX (VPI bits, 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unknown VCs, oam cells) are made. Ideally all policy items should be 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds configurable at module load (if not actually on-demand), however, 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds only the vpi vs vci bit allocation can be specified at insmod. 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4. Shutdown 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This is in response to module_cleaup. No VCs are in use and the card 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds should be idle; it is reset. 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds II Driver software (as it should be) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0. Traffic Parameters 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The traffic classes (not an enumeration) are currently: ATM_NONE (no 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds traffic), ATM_UBR, ATM_CBR, ATM_VBR and ATM_ABR, ATM_ANYCLASS 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (compatible with everything). Together with (perhaps only some of) 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the following items they make up the traffic specification. 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_trafprm { 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char traffic_class; traffic class (ATM_UBR, ...) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_pcr; maximum PCR in cells per second 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pcr; desired PCR in cells per second 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int min_pcr; minimum PCR in cells per second 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_cdv; maximum CDV in microseconds 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int max_sdu; maximum SDU in bytes 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Note that these denote bandwidth available not bandwidth used; the 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds possibilities according to ATMF are: 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Real Time (cdv and max CDT given) 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CBR(pcr) pcr bandwidth always available 17325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi rtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Non Real Time 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi nrtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds UBR() 17925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi ABR(mcr,pcr) mcr bandwidth always available, up to pcr (depending) too 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mbs is max burst size (bucket) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr and scr have associated cdvt values 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcr is like scr but has no cdtv 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdtv may differ at each hop 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Some of the above items are qos items (as opposed to traffic 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parameters). We have nothing to do with qos. All except ABR can have 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds their traffic parameters converted to GCRA parameters. The GCRA may 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be implemented as a (real-number) leaky bucket. The GCRA can be used 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in complicated ways by switches and in simpler ways by end-stations. 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds It can be used both to filter incoming cells and shape out-going 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cells. 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM Linux actually supports: 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_NONE() (no traffic in this direction) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_UBR(max_frame_size) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_CBR(max/min_pcr, max_cdv, max_frame_size) 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0 or ATM_MAX_PCR are used to indicate maximum available PCR 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds A traffic specification consists of the AAL type and separate 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds traffic specifications for either direction. In ATM Linux it is: 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_qos { 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_trafprm txtp; 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_trafprm rxtp; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char aal; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AAL types are: 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_NO_AAL AAL not specified 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_AAL0 "raw" ATM cells 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_AAL1 AAL1 (CBR) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_AAL2 AAL2 (VBR) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_AAL34 AAL3/4 (data) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_AAL5 AAL5 (data) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SAAL signaling AAL 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The Horizon has support for AAL frame types: 0, 3/4 and 5. However, 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it does not implement AAL 3/4 SAR and it has a different notion of 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "raw cell" to ATM Linux's (48 bytes vs. 52 bytes) so neither are 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds supported by this driver. 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The Horizon has limited support for ABR (including UBR), VBR and 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CBR. Each TX channel has a bucket (containing up to 31 cell units) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and two timers (PCR and SCR) associated with it that can be used to 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds govern cell emissions and host notification (in the case of ABR this 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is presumably so that RM cells may be emitted at appropriate times). 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The timers may either be disabled or may be set to any of 240 values 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (determined by the clock crystal, a fixed (?) per-device divider, a 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds configurable divider and a configurable timer preload value). 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds At the moment only UBR and CBR are supported by the driver. VBR will 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be supported as soon as ATM for Linux supports it. ABR support is 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds very unlikely as RM cell handling is completely up to the driver. 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. TX (TX channel setup and TX transfer) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The TX half of the driver owns the TX Horizon registers. The TX 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds component in the IRQ handler is the BM completion handler. This can 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds only be entered when tx_busy is true (enforced by hardware). The 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds other TX component can only be entered when tx_busy is false 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (enforced by driver). So TX is single-threaded. 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Apart from a minor optimisation to not re-select the last channel, 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the TX send component works as follows: 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Atomic test and set tx_busy until we succeed; we should implement 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds some sort of timeout so that tx_busy will never be stuck at true. 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If no TX channel is set up for this VC we wait for an idle one (if 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds necessary) and set it up. 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds At this point we have a TX channel ready for use. We wait for enough 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffers to become available then start a TX transmit (set the TX 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds descriptor, schedule transfer, exit). 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The IRQ component handles TX completion (stats, free buffer, tx_busy 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unset, exit). We also re-schedule further transfers for the same 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds frame if needed. 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX setup in more detail: 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX open is a nop, the relevant information is held in the hrz_vcc 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (vcc->dev_data) structure and is "cached" on the card. 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX close gets the TX lock and clears the channel from the "cache". 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. RX (Data Available and RX transfer) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The RX half of the driver owns the RX registers. There are two RX 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds components in the IRQ handler: the data available handler deals with 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fresh data that has arrived on the card, the BM completion handler 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is very similar to the TX completion handler. The data available 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handler grabs the rx_lock and it is only released once the data has 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds been discarded or completely transferred to the host. The BM 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds completion handler only runs when the lock is held; the data 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds available handler is locked out over the same period. 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Data available on the card triggers an interrupt. If the data is not 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds suitable for our existing RX channels or we cannot allocate a buffer 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it is flushed. Otherwise an RX receive is scheduled. Multiple RX 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transfers may be scheduled for the same frame. 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RX setup in more detail: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RX open... 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RX close... 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds III Hardware Bugs 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0. Byte vs Word addressing of adapter RAM. 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds A design feature; see the .h file (especially the memory map). 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. Bus Master Data Transfers (original Horizon only, fixed in Ultra) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The host must not start a transmit direction transfer at a 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds non-four-byte boundary in host memory. Instead the host should 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds perform a byte, or a two byte, or one byte followed by two byte 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transfer in order to start the rest of the transfer on a four byte 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds boundary. RX is OK. 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Simultaneous transmit and receive direction bus master transfers are 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds not allowed. 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The simplest solution to these two is to always do PIO (never DMA) 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in the TX direction on the original Horizon. More complicated 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds solutions are likely to hurt my brain. 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. Loss of buffer on close VC 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds When a VC is being closed, the buffer associated with it is not 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds returned to the pool. The host must store the reference to this 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffer and when opening a new VC then give it to that new VC. 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The host intervention currently consists of stacking such a buffer 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pointer at VC close and checking the stack at VC open. 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3. Failure to close a VC 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If a VC is currently receiving a frame then closing the VC may fail 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and the frame continues to be received. 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The solution is to make sure any received frames are flushed when 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ready. This is currently done just before the solution to 2. 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4. PCI bus (original Horizon only, fixed in Ultra) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Reading from the data port prior to initialisation will hang the PCI 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus. Just don't do that then! We don't. 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IV To Do List 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Timer code may be broken. 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Allow users to specify buffer allocation split for TX and RX. 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Deal once and for all with buggy VC close. 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Handle interrupted and/or non-blocking operations. 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Change some macros to functions and move from .h to .c. 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Try to limit the number of TX frames each VC may have queued, in 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds order to reduce the chances of TX buffer exhaustion. 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Implement VBR (bucket and timers not understood) and ABR (need to 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do RM cells manually); also no Linux support for either. 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds . Implement QoS changes on open VCs (involves extracting parts of VC open 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and close into separate functions and using them to make changes). 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** globals **********/ 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void do_housekeeping (unsigned long arg); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short debug = 0; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short vpi_bits = 0; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_tx_size = 9000; 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int max_rx_size = 9000; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char pci_lat = 0; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** access functions **********/ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read / Write Horizon registers */ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wr_regl (const hrz_dev * dev, unsigned char reg, u32 data) { 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outl (cpu_to_le32 (data), dev->iobase + reg); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 rd_regl (const hrz_dev * dev, unsigned char reg) { 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return le32_to_cpu (inl (dev->iobase + reg)); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wr_regw (const hrz_dev * dev, unsigned char reg, u16 data) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw (cpu_to_le16 (data), dev->iobase + reg); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 rd_regw (const hrz_dev * dev, unsigned char reg) { 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return le16_to_cpu (inw (dev->iobase + reg)); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wrs_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsb (dev->iobase + reg, addr, len); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rds_regb (const hrz_dev * dev, unsigned char reg, void * addr, u32 len) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds insb (dev->iobase + reg, addr, len); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Read / Write to a given address in Horizon buffer memory. 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Interrupts must be disabled between the address register and data 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port accesses as these must form an atomic operation. */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wr_mem (const hrz_dev * dev, HDW * addr, u32 data) { 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEM_WR_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEMORY_PORT_OFF, data); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 rd_mem (const hrz_dev * dev, HDW * addr) { 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEM_RD_ADDR_REG_OFF, (addr - (HDW *) 0) * sizeof(HDW)); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rd_regl (dev, MEMORY_PORT_OFF); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wr_framer (const hrz_dev * dev, u32 addr, u32 data) { 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEM_WR_ADDR_REG_OFF, (u32) addr | 0x80000000); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEMORY_PORT_OFF, data); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u32 rd_framer (const hrz_dev * dev, u32 addr) { 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MEM_RD_ADDR_REG_OFF, (u32) addr | 0x80000000); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rd_regl (dev, MEMORY_PORT_OFF); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** specialised access functions **********/ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* RX */ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void FLUSH_RX_CHANNEL (hrz_dev * dev, u16 channel) { 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_CHANNEL_PORT_OFF, FLUSH_CHANNEL | channel); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4292cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void WAIT_FLUSH_RX_COMPLETE (hrz_dev * dev) { 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & FLUSH_CHANNEL) 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void SELECT_RX_CHANNEL (hrz_dev * dev, u16 channel) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_CHANNEL_PORT_OFF, channel); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4402cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void WAIT_UPDATE_COMPLETE (hrz_dev * dev) { 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rd_regw (dev, RX_CHANNEL_PORT_OFF) & RX_CHANNEL_UPDATE_IN_PROGRESS) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TX */ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void SELECT_TX_CHANNEL (hrz_dev * dev, u16 tx_channel) { 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, TX_CHANNEL_PORT_OFF, tx_channel); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Update or query one configuration parameter of a particular channel. */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void update_tx_channel_config (hrz_dev * dev, short chan, u8 mode, u16 value) { 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chan * TX_CHANNEL_CONFIG_MULT | mode); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF, value); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 query_tx_channel_config (hrz_dev * dev, short chan, u8 mode) { 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF, 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chan * TX_CHANNEL_CONFIG_MULT | mode); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rd_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** dump functions **********/ 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) { 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_HORIZON 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char * data = skb->data; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDB (DBG_DATA, "%s(%u) ", prefix, vc); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<skb->len && i < 256;i++) 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDM (DBG_DATA, "%02x ", data[i]); 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDE (DBG_DATA,""); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) prefix; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) vc; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) skb; 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void dump_regs (hrz_dev * dev) { 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_HORIZON 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "CONTROL 0: %#x", rd_regl (dev, CONTROL_0_REG)); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "RX CONFIG: %#x", rd_regw (dev, RX_CONFIG_OFF)); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "TX CONFIG: %#x", rd_regw (dev, TX_CONFIG_OFF)); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "TX STATUS: %#x", rd_regw (dev, TX_STATUS_OFF)); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "IRQ ENBLE: %#x", rd_regl (dev, INT_ENABLE_REG_OFF)); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_REGS, "IRQ SORCE: %#x", rd_regl (dev, INT_SOURCE_REG_OFF)); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) dev; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void dump_framer (hrz_dev * dev) { 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_HORIZON 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDB (DBG_REGS, "framer registers:"); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 0x10; ++i) 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDM (DBG_REGS, " %02x", rd_framer (dev, i)); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTDE (DBG_REGS,""); 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (void) dev; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** VPI/VCI <-> (RX) channel conversions **********/ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* RX channels are 10 bit integers, these fns are quite paranoid */ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) { 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vci_bits = 10 - vpi_bits; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((channel & RX_CHANNEL_MASK) == channel) { 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vci = channel & ((~0)<<vci_bits); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vpi = channel >> vci_bits; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return channel ? 0 : -EINVAL; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) { 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short vci_bits = 10 - vpi_bits; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (0 <= vpi && vpi < 1<<vpi_bits && 0 <= vci && vci < 1<<vci_bits) { 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *channel = vpi<<vci_bits | vci; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return *channel ? 0 : -EINVAL; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** decode RX queue entries **********/ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 rx_q_entry_to_length (u32 x) { 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x & RX_Q_ENTRY_LENGTH_MASK; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u16 rx_q_entry_to_rx_channel (u32 x) { 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (x>>RX_Q_ENTRY_CHANNEL_SHIFT) & RX_CHANNEL_MASK; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Cell Transmit Rate Values 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the cell transmit rate (cells per sec) can be set to a variety of 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * different values by specifying two parameters: a timer preload from 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 to 16 (stored as 0 to 15) and a clock divider (2 to the power of 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an exponent from 0 to 14; the special value 15 disables the timer). 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cellrate = baserate / (preload * 2^divider) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The maximum cell rate that can be specified is therefore just the 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base rate. Halving the preload is equivalent to adding 1 to the 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * divider and so values 1 to 8 of the preload are redundant except 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the case of a maximal divider (14). 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Given a desired cell rate, an algorithm to determine the preload 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and divider is: 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a) x = baserate / cellrate, want p * 2^d = x (as far as possible) 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * b) if x > 16 * 2^14 then set p = 16, d = 14 (min rate), done 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if x <= 16 then set p = x, d = 0 (high rates), done 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * c) now have 16 < x <= 2^18, or 1 < x/16 <= 2^14 and we want to 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * know n such that 2^(n-1) < x/16 <= 2^n, so slide a bit until 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we find the range (n will be between 1 and 14), set d = n 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * d) Also have 8 < x/2^n <= 16, so set p nearest x/2^n 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The algorithm used below is a minor variant of the above. 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The base rate is derived from the oscillator frequency (Hz) using a 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fixed divider: 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * baserate = freq / 32 in the case of some Unknown Card 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * baserate = freq / 8 in the case of the Horizon 25 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * baserate = freq / 8 in the case of the Horizon Ultra 155 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Horizon cards have oscillators and base rates as follows: 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Card Oscillator Base Rate 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unknown Card 33 MHz 1.03125 MHz (33 MHz = PCI freq) 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Horizon 25 32 MHz 4 MHz 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Horizon Ultra 155 40 MHz 5 MHz 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The following defines give the base rates in Hz. These were 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previously a factor of 100 larger, no doubt someone was using 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cps*100. 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BR_UKN 1031250l 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BR_HRZ 4000000l 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BR_ULT 5000000l 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// d is an exponent 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CR_MIND 0 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CR_MAXD 14 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// p ranges from 1 to a power of 2 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CR_MAXPEXP 4 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int make_rate (const hrz_dev * dev, u32 c, rounding r, 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 * bits, unsigned int * actual) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // note: rounding the rate down means rounding 'p' up 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned long br = test_bit(ultra, &dev->flags) ? BR_ULT : BR_HRZ; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 div = CR_MIND; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 pre; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // br_exp and br_man are used to avoid overflowing (c*maxp*2^d) in 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // the tests below. We could think harder about exact possibilities 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // of failure... 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long br_man = br; 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int br_exp = 0; 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_FLOW, "make_rate b=%lu, c=%u, %s", br, c, 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r == round_up ? "up" : r == round_down ? "down" : "nearest"); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // avoid div by zero 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!c) { 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_ERR, "zero rate is not allowed!"); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (br_exp < CR_MAXPEXP + CR_MIND && (br_man % 2 == 0)) { 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds br_man = br_man >> 1; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++br_exp; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (br >>br_exp) <<br_exp == br and 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // br_exp <= CR_MAXPEXP+CR_MIND 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br_man <= (c << (CR_MAXPEXP+CR_MIND-br_exp))) { 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Equivalent to: B <= (c << (MAXPEXP+MIND)) 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // take care of rounding 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (r) { 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case round_down: 6406a19309db0a02d821494f4df754046c85a230627Julia Lawall pre = DIV_ROUND_UP(br, c<<div); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but p must be non-zero 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pre) 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pre = 1; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case round_nearest: 6468b97c7c283c5ba8f9f4dabd418fd7dcfcc8a387eJulia Lawall pre = DIV_ROUND_CLOSEST(br, c<<div); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but p must be non-zero 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pre) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pre = 1; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* round_up */ 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pre = br/(c<<div); 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but p must be non-zero 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pre) 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "A: p=%u, d=%u", pre, div); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto got_it; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // at this point we have 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // d == MIND and (c << (MAXPEXP+MIND)) < B 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (div < CR_MAXD) { 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds div++; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (br_man <= (c << (CR_MAXPEXP+div-br_exp))) { 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Equivalent to: B <= (c << (MAXPEXP+d)) 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // c << (MAXPEXP+d-1) < B <= c << (MAXPEXP+d) 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // 1 << (MAXPEXP-1) < B/2^d/c <= 1 << MAXPEXP 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // MAXP/2 < B/c2^d <= MAXP 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // take care of rounding 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (r) { 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case round_down: 6736a19309db0a02d821494f4df754046c85a230627Julia Lawall pre = DIV_ROUND_UP(br, c<<div); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case round_nearest: 6768b97c7c283c5ba8f9f4dabd418fd7dcfcc8a387eJulia Lawall pre = DIV_ROUND_CLOSEST(br, c<<div); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* round_up */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pre = br/(c<<div); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "B: p=%u, d=%u", pre, div); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto got_it; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // at this point we have 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // d == MAXD and (c << (MAXPEXP+MAXD)) < B 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but we cannot go any higher 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // take care of rounding 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r == round_down) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pre = 1 << CR_MAXPEXP; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "C: p=%u, d=%u", pre, div); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsgot_it: 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // paranoia 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (div > CR_MAXD || (!pre) || pre > 1<<CR_MAXPEXP) { 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "set_cr internal failure: d=%u p=%u", 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds div, pre); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bits) 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *bits = (div<<CLOCK_SELECT_SHIFT) | (pre-1); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (actual) { 7036a19309db0a02d821494f4df754046c85a230627Julia Lawall *actual = DIV_ROUND_UP(br, pre<<div); 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "actual rate: %u", *actual); 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int make_rate_with_tolerance (const hrz_dev * dev, u32 c, rounding r, unsigned int tol, 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 * bit_pattern, unsigned int * actual) { 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int my_actual; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_FLOW, "make_rate_with_tolerance c=%u, %s, tol=%u", 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds c, (r == round_up) ? "up" : (r == round_down) ? "down" : "nearest", tol); 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!actual) 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // actual rate is not returned 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds actual = &my_actual; 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (make_rate (dev, c, round_nearest, bit_pattern, actual)) 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // should never happen as round_nearest always succeeds 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (c - tol <= *actual && *actual <= c + tol) 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // within tolerance 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // intolerant, try rounding instead 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return make_rate (dev, c, r, bit_pattern, actual); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** Listen on a VC **********/ 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_open_rx (hrz_dev * dev, u16 channel) { 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // is there any guarantee that we don't get two simulataneous 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // identical calls of this function from different processes? yes 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rate_lock 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 channel_type; // u16? 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 buf_ptr = RX_CHANNEL_IDLE; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ch_desc * rx_desc = &memmap->rx_descs[channel]; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_open_rx %x", channel); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dev->mem_lock, flags); 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel_type = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // very serious error, should never occur 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel_type != RX_CHANNEL_DISABLED) { 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_ERR|DBG_VCC, "RX channel for VC already open"); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; // clean up? 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Give back spare buffer 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->noof_spare_buffers) { 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_ptr = dev->spare_buffers[--dev->noof_spare_buffers]; 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC, "using a spare buffer: %u", buf_ptr); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // should never occur 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf_ptr == RX_CHANNEL_DISABLED || buf_ptr == RX_CHANNEL_IDLE) { 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but easy to recover from 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_ERR|DBG_VCC, "bad spare buffer pointer, using IDLE"); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_ptr = RX_CHANNEL_IDLE; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC, "using IDLE buffer pointer"); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Channel is currently disabled so change its status to idle 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // do we really need to save the flags again? 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dev->mem_lock, flags); 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->wr_buf_type, 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_ptr | CHANNEL_TYPE_AAL5 | FIRST_CELL_OF_AAL5_FRAME); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (buf_ptr != RX_CHANNEL_IDLE) 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->rd_buf_type, buf_ptr); 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rxer->rate = make_rate (qos->peak_cells); 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_open_rx ok"); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** change vc rate for a given vc **********/ 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hrz_change_vc_qos (ATM_RXER * rxer, MAAL_QOS * qos) { 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rxer->rate = make_rate (qos->peak_cells); 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** free an skb (as per ATM device driver documentation) **********/ 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8012cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void hrz_kfree_skb (struct sk_buff * skb) { 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ATM_SKB(skb)->vcc->pop) { 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any (skb); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** cancel listen on a VC **********/ 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hrz_close_rx (hrz_dev * dev, u16 vc) { 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 value; 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 r1, r2; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ch_desc * rx_desc = &memmap->rx_descs[vc]; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int was_idle = 0; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dev->mem_lock, flags); 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == RX_CHANNEL_DISABLED) { 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // I suppose this could happen once we deal with _NONE traffic properly 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC, "closing VC: RX channel %u already disabled", vc); 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (value == RX_CHANNEL_IDLE) 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was_idle = 1; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dev->mem_lock, flags); 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->wr_buf_type, RX_CHANNEL_DISABLED); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((rd_mem (dev, &rx_desc->wr_buf_type) & BUFFER_PTR_MASK) == RX_CHANNEL_DISABLED) 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was_idle = 0; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (was_idle) { 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_FLUSH_RX_COMPLETE(dev); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // XXX Is this all really necessary? We can rely on the rx_data_av 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // handler to discard frames that remain queued for delivery. If the 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // worry is that immediately reopening the channel (perhaps by a 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // different process) may cause some data to be mis-delivered then 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // there may still be a simpler solution (such as busy-waiting on 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rx_busy once the channel is disabled or before a new one is 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // opened - does this leave any holes?). Arguably setting up and 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // tearing down the TX and RX halves of each virtual circuit could 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // most safely be done within ?x_busy protected regions. 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // OK, current changes are that Simon's marker is disabled and we DO 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // look for NULL rxer elsewhere. The code here seems flush frames 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // and then remember the last dead cell belonging to the channel 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // just disabled - the cell gets relinked at the next vc_open. 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // However, when all VCs are closed or only a few opened there are a 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // handful of buffers that are unusable. 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Does anyone feel like documenting spare_buffers properly? 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Does anyone feel like fixing this in a nicer way? 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Flush any data which is left in the channel 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (;;) { 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Change the rx channel port to something different to the RX 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // channel we are trying to close to force Horizon to flush the rx 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // channel read and write pointers. 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 other = vc^(RX_CHANS/2); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SELECT_RX_CHANNEL (dev, other); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_UPDATE_COMPLETE (dev); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r1 = rd_mem (dev, &rx_desc->rd_buf_type); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Select this RX channel. Flush doesn't seem to work unless we 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // select an RX channel before hand 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SELECT_RX_CHANNEL (dev, vc); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_UPDATE_COMPLETE (dev); 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Attempt to flush a frame on this RX channel 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FLUSH_RX_CHANNEL (dev, vc); 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_FLUSH_RX_COMPLETE (dev); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Force Horizon to flush rx channel read and write pointers as before 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SELECT_RX_CHANNEL (dev, other); 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_UPDATE_COMPLETE (dev); 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r2 = rd_mem (dev, &rx_desc->rd_buf_type); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC|DBG_RX, "r1 = %u, r2 = %u", r1, r2); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (r1 == r2) { 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->spare_buffers[dev->noof_spare_buffers++] = (u16)r1; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_q_entry * wr_ptr = &memmap->rx_q_entries[rd_regw (dev, RX_QUEUE_WR_PTR_OFF)]; 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_q_entry * rd_ptr = dev->rx_q_entry; 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC|DBG_RX, "rd_ptr = %u, wr_ptr = %u", rd_ptr, wr_ptr); 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rd_ptr != wr_ptr) { 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 x = rd_mem (dev, (HDW *) rd_ptr); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vc == rx_q_entry_to_rx_channel (x)) { 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x |= SIMONS_DODGEY_MARKER; 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_VCC|DBG_WARN, "marking a frame as dodgey"); 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, (HDW *) rd_ptr, x); 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rd_ptr == dev->rx_q_wrap) 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr = dev->rx_q_reset; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr++; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** schedule RX transfers **********/ 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// Note on tail recursion: a GCC developer said that it is not likely 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// to be fixed soon, so do not define TAILRECUSRIONWORKS unless you 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// are sure it does as you may otherwise overflow the kernel stack. 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 94825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi// giving this fn a return value would help GCC, allegedly 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void rx_schedule (hrz_dev * dev, int irq) { 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rx_bytes; 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pio_instead = 0; 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef TAILRECURSIONWORKS 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pio_instead) { 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // bytes waiting for RX transfer 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_bytes = dev->rx_bytes; 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_count = 0; 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rd_regl (dev, MASTER_RX_COUNT_REG_OFF)) { 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_WARN, "RX error: other PCI Bus Master RX still in progress!"); 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++spin_count > 10) { 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_ERR, "spun out waiting PCI Bus Master RX completion"); 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit (rx_busy, &dev->flags); 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (dev->rx_skb); 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // this code follows the TX code but (at the moment) there is only 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // one region - the skb itself. I don't know if this will change, 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // but it doesn't hurt to have the code here, disabled. 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes) { 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // start next transfer within same region 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes <= MAX_PIO_COUNT) { 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(pio)"); 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes <= MAX_TRANSFER_COUNT) { 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(simple or last multi)"); 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_bytes = 0; 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(continuing multi)"); 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_bytes = MAX_TRANSFER_COUNT; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rx_bytes == 0 -- we're between regions 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // regions remaining to transfer 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rx_regions = dev->rx_regions; 9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int rx_regions = 0; 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_regions) { 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // start a new region 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_addr = dev->rx_iovec->iov_base; 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_bytes = dev->rx_iovec->iov_len; 10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++dev->rx_iovec; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_regions = rx_regions - 1; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes <= MAX_PIO_COUNT) { 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(pio)"); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes <= MAX_TRANSFER_COUNT) { 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(full region)"); 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_bytes = 0; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_BUS, "(start multi region)"); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_bytes = rx_bytes - MAX_TRANSFER_COUNT; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_bytes = MAX_TRANSFER_COUNT; 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rx_regions == 0 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // that's all folks - end of frame 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff * skb = dev->rx_skb; 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // dev->rx_iovec = 0; 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FLUSH_RX_CHANNEL (dev, dev->rx_channel); 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_skb ("<<<", dev->rx_channel, skb); 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_SKB, "push %p %u", skb->data, skb->len); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_vcc * vcc = ATM_SKB(skb)->vcc; 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // VC layer stats 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&vcc->stats->rx); 1039a61bbcf28a8cb0ba56f8193d512f7222e711a294Patrick McHardy __net_timestamp(skb); 104025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi // end of our responsibility 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->push (vcc, skb); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // note: writing RX_COUNT clears any interrupt condition 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_bytes) { 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pio_instead) { 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq) 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rds_regb (dev, DATA_PORT_OFF, dev->rx_addr, rx_bytes); 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_ADDR_REG_OFF, virt_to_bus (dev->rx_addr)); 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_COUNT_REG_OFF, rx_bytes); 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_addr += rx_bytes; 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq) 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // allow another RX thread to start 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_ON(dev); 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit (rx_busy, &dev->flags); 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "cleared rx_busy for dev %p", dev); 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef TAILRECURSIONWORKS 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // and we all bless optimised tail calls 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pio_instead) 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rx_schedule (dev, 0); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // grrrrrrr! 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = 0; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** handle RX bus master complete events **********/ 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10812cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void rx_bus_master_complete_handler (hrz_dev * dev) { 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_bit (rx_busy, &dev->flags)) { 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_schedule (dev, 1); 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_ERR, "unexpected RX bus master completion"); 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // clear interrupt condition on adapter 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_RX_COUNT_REG_OFF, 0); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** (queue to) become the next TX thread **********/ 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10942cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic int tx_hold (hrz_dev * dev) { 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "sleeping at tx lock %p %lu", dev, dev->flags); 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wait_event_interruptible(dev->tx_queue, (!test_and_set_bit(tx_busy, &dev->flags))); 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "woken at tx lock %p %lu", dev, dev->flags); 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (signal_pending (current)) 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "set tx_busy for dev %p", dev); 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** allow another TX thread to start **********/ 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void tx_release (hrz_dev * dev) { 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit (tx_busy, &dev->flags); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "cleared tx_busy for dev %p", dev); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wake_up_interruptible (&dev->tx_queue); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** schedule TX transfers **********/ 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void tx_schedule (hrz_dev * const dev, int irq) { 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tx_bytes; 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int append_desc = 0; 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pio_instead = 0; 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef TAILRECURSIONWORKS 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (pio_instead) { 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // bytes in current region waiting for TX transfer 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_bytes = dev->tx_bytes; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_count = 0; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (rd_regl (dev, MASTER_TX_COUNT_REG_OFF)) { 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_WARN, "TX error: other PCI Bus Master TX still in progress!"); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++spin_count > 10) { 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "spun out waiting PCI Bus Master TX completion"); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (dev->tx_skb); 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_bytes) { 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // start next transfer within same region 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(pio)"); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_bytes <= MAX_TRANSFER_COUNT) { 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(simple or last multi)"); 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev->tx_iovec) { 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // end of last region 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds append_desc = 1; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = 0; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(continuing multi)"); 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_bytes = MAX_TRANSFER_COUNT; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // tx_bytes == 0 -- we're between regions 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // regions remaining to transfer 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tx_regions = dev->tx_regions; 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_regions) { 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // start a new region 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_addr = dev->tx_iovec->iov_base; 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_bytes = dev->tx_iovec->iov_len; 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++dev->tx_iovec; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_regions = tx_regions - 1; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!test_bit (ultra, &dev->flags) || tx_bytes <= MAX_PIO_COUNT) { 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(pio)"); 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pio_instead = 1; 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_bytes <= MAX_TRANSFER_COUNT) { 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(full region)"); 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = 0; 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "(start multi region)"); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = tx_bytes - MAX_TRANSFER_COUNT; 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_bytes = MAX_TRANSFER_COUNT; 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // tx_regions == 0 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // that's all folks - end of frame 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff * skb = dev->tx_skb; 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_iovec = NULL; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // VC layer stats 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atomic_inc(&ATM_SKB(skb)->vcc->stats->tx); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // free the skb 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // note: writing TX_COUNT clears any interrupt condition 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_bytes) { 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pio_instead) { 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq) 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wrs_regb (dev, DATA_PORT_OFF, dev->tx_addr, tx_bytes); 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (append_desc) 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, TX_DESCRIPTOR_PORT_OFF, cpu_to_be32 (dev->tx_skb->len)); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_ADDR_REG_OFF, virt_to_bus (dev->tx_addr)); 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (append_desc) 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, TX_DESCRIPTOR_REG_OFF, cpu_to_be32 (dev->tx_skb->len)); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds append_desc 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? tx_bytes | MASTER_TX_AUTO_APPEND_DESC 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds : tx_bytes); 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_addr += tx_bytes; 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq) 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_ON(dev); 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef TAILRECURSIONWORKS 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // and we all bless optimised tail calls 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pio_instead) 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tx_schedule (dev, 0); 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // grrrrrrr! 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = 0; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** handle TX bus master complete events **********/ 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12372cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void tx_bus_master_complete_handler (hrz_dev * dev) { 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_bit (tx_busy, &dev->flags)) { 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_schedule (dev, 1); 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "unexpected TX bus master completion"); 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // clear interrupt condition on adapter 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, MASTER_TX_COUNT_REG_OFF, 0); 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** move RX Q pointer to next item in circular buffer **********/ 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// called only from IRQ sub-handler 12512cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic u32 rx_queue_entry_next (hrz_dev * dev) { 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 rx_queue_entry; 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dev->mem_lock); 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_queue_entry = rd_mem (dev, &dev->rx_q_entry->entry); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->rx_q_entry == dev->rx_q_wrap) 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_q_entry = dev->rx_q_reset; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_q_entry++; 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_QUEUE_RD_PTR_OFF, dev->rx_q_entry - dev->rx_q_reset); 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dev->mem_lock); 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return rx_queue_entry; 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** handle RX disabled by device **********/ 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void rx_disabled_handler (hrz_dev * dev) { 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // count me please 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_WARNING, "RX was disabled!"); 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** handle RX data received by device **********/ 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// called from IRQ handler 12752cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void rx_data_av_handler (hrz_dev * dev) { 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 rx_queue_entry; 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 rx_queue_entry_flags; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 rx_len; 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 rx_channel; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_data_av_handler"); 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // try to grab rx lock (not possible during RX bus mastering) 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit (rx_busy, &dev->flags)) { 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "locked out of rx lock"); 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "set rx_busy for dev %p", dev); 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // lock is cleared if we fail now, o/w after bus master completion 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_OFF(dev); 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_queue_entry = rx_queue_entry_next (dev); 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_len = rx_q_entry_to_length (rx_queue_entry); 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_channel = rx_q_entry_to_rx_channel (rx_queue_entry); 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WAIT_FLUSH_RX_COMPLETE (dev); 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SELECT_RX_CHANNEL (dev, rx_channel); 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "rx_queue_entry is: %#x", rx_queue_entry); 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_queue_entry_flags = rx_queue_entry & (RX_CRC_32_OK|RX_COMPLETE_FRAME|SIMONS_DODGEY_MARKER); 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!rx_len) { 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (at least) bus-mastering breaks if we try to handle a 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // zero-length frame, besides AAL5 does not support them 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "zero-length frame!"); 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_queue_entry_flags &= ~RX_COMPLETE_FRAME; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_queue_entry_flags & SIMONS_DODGEY_MARKER) { 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX|DBG_ERR, "Simon's marker detected!"); 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_queue_entry_flags == (RX_CRC_32_OK | RX_COMPLETE_FRAME)) { 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_vcc * atm_vcc; 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "got a frame on rx_channel %x len %u", rx_channel, rx_len); 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atm_vcc = dev->rxer[rx_channel]; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // if no vcc is assigned to this channel, we should drop the frame 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (is this what SIMONS etc. was trying to achieve?) 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc) { 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rx_len <= atm_vcc->qos.rxtp.max_sdu) { 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff * skb = atm_alloc_charge (atm_vcc, rx_len, GFP_ATOMIC); 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb) { 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // remember this so we can push it later 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_skb = skb; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // remember this so we can flush it later 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_channel = rx_channel; 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // prepare socket buffer 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put (skb, rx_len); 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SKB(skb)->vcc = atm_vcc; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // simple transfer 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // dev->rx_regions = 0; 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // dev->rx_iovec = 0; 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_bytes = rx_len; 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_addr = skb->data; 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_RX, "RX start simple transfer (addr %p, len %d)", 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data, rx_len); 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // do the business 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_schedule (dev, 0); 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_SKB|DBG_WARN, "failed to get skb"); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_INFO, "frame received on TX-only VC %x", rx_channel); 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // do we count this? 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_WARNING, "dropped over-size frame"); 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // do we count this? 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_WARN|DBG_VCC|DBG_RX, "no VCC for this frame (VC closed)"); 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // do we count this? 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Wait update complete ? SPONG 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // RX was aborted 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_ON(dev); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FLUSH_RX_CHANNEL (dev,rx_channel); 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit (rx_busy, &dev->flags); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** interrupt handler **********/ 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138706efcad0d43a5491602f7d7bfc1ce997cdb0d062Jeff Garzikstatic irqreturn_t interrupt_handler(int irq, void *dev_id) 138806efcad0d43a5491602f7d7bfc1ce997cdb0d062Jeff Garzik{ 138906efcad0d43a5491602f7d7bfc1ce997cdb0d062Jeff Garzik hrz_dev *dev = dev_id; 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 int_source; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int irq_ok; 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // definitely for us 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_ok = 0; 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF) 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & INTERESTING_INTERRUPTS)) { 13992cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenko // In the interests of fairness, the handlers below are 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // called in sequence and without immediate return to the head of 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // the while loop. This is only of issue for slow hosts (or when 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // debugging messages are on). Really slow hosts may find a fast 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // sender keeps them permanently in the IRQ handler. :( 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (only an issue for slow hosts) RX completion goes before 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rx_data_av as the former implies rx_busy and so the latter 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // would just abort. If it reschedules another transfer 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (continuing the same frame) then it will not clear rx_busy. 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (only an issue for slow hosts) TX completion goes before RX 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // data available as it is a much shorter routine - there is the 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // chance that any further transfers it schedules will be complete 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // by the time of the return to the head of the while loop 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (int_source & RX_BUS_MASTER_COMPLETE) { 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++irq_ok; 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ|DBG_BUS|DBG_RX, "rx_bus_master_complete asserted"); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_bus_master_complete_handler (dev); 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (int_source & TX_BUS_MASTER_COMPLETE) { 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++irq_ok; 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ|DBG_BUS|DBG_TX, "tx_bus_master_complete asserted"); 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_bus_master_complete_handler (dev); 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (int_source & RX_DATA_AV) { 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++irq_ok; 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ|DBG_RX, "rx_data_av asserted"); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_data_av_handler (dev); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_ok) { 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ, "work done: %u", irq_ok); 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ|DBG_WARN, "spurious interrupt source: %#x", int_source); 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler done: %p", dev_id); 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq_ok) 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** housekeeping **********/ 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void do_housekeeping (unsigned long arg) { 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // just stats at the moment 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = (hrz_dev *) arg; 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // collect device-specific (not driver/atm-linux) stats here 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_cell_count += rd_regw (dev, TX_CELL_COUNT_OFF); 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_cell_count += rd_regw (dev, RX_CELL_COUNT_OFF); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hec_error_count += rd_regw (dev, HEC_ERROR_COUNT_OFF); 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->unassigned_cell_count += rd_regw (dev, UNASSIGNED_CELL_COUNT_OFF); 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer (&dev->housekeeping, jiffies + HZ/10); 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** find an idle channel for TX and set it up **********/ 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// called with tx_busy set 14632cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic short setup_idle_tx_channel (hrz_dev * dev, hrz_vcc * vcc) { 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short idle_channels; 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short tx_channel = -1; 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int spin_count; 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_TX, "setup_idle_tx_channel %p", dev); 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // better would be to fail immediately, the caller can then decide whether 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // to wait or drop (depending on whether this is UBR etc.) 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_count = 0; 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!(idle_channels = rd_regw (dev, TX_STATUS_OFF) & IDLE_CHANNELS_MASK)) { 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_WARN, "waiting for idle TX channel"); 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // delay a bit here 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++spin_count > 100) { 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "spun out waiting for idle TX channel"); 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // got an idle channel 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // tx_idle ensures we look for idle channels in RR order 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int chan = dev->tx_idle; 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int keep_going = 1; 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (keep_going) { 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (idle_channels & (1<<chan)) { 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_channel = chan; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds keep_going = 0; 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++chan; 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (chan == TX_CHANS) 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chan = 0; 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_idle = chan; 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set up the channel we found 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise the cell header in the transmit channel descriptor 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // a.k.a. prepare the channel and remember that we have done so. 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_ch_desc * tx_desc = &memmap->tx_descs[tx_channel]; 1506b925556cc9e82b32ab68a7620b247f47193501a7Dave Jones u32 rd_ptr; 1507b925556cc9e82b32ab68a7620b247f47193501a7Dave Jones u32 wr_ptr; 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 channel = vcc->channel; 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave (&dev->mem_lock, flags); 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Update the transmit channel record. 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_channel_record[tx_channel] = channel; 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // xBR channel 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_tx_channel_config (dev, tx_channel, RATE_TYPE_ACCESS, 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_xbr_bits); 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Update the PCR counter preload value etc. 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_tx_channel_config (dev, tx_channel, PCR_TIMER_ACCESS, 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_pcr_bits); 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc->tx_xbr_bits == VBR_RATE_TYPE) { 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // SCR timer 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_tx_channel_config (dev, tx_channel, SCR_TIMER_ACCESS, 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_scr_bits); 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Bucket size... 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_tx_channel_config (dev, tx_channel, BUCKET_CAPACITY_ACCESS, 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_bucket_bits); 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // ... and fullness 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_tx_channel_config (dev, tx_channel, BUCKET_FULLNESS_ACCESS, 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_bucket_bits); 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise the read and write buffer pointers 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr = rd_mem (dev, &tx_desc->rd_buf_type) & BUFFER_PTR_MASK; 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_ptr = rd_mem (dev, &tx_desc->wr_buf_type) & BUFFER_PTR_MASK; 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // idle TX channels should have identical pointers 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rd_ptr != wr_ptr) { 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "TX buffer pointers are broken!"); 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // spin_unlock... return -E... 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // I wonder if gcc would get rid of one of the pointer aliases 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "TX buffer pointers are: rd %x, wr %x.", 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr, wr_ptr); 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (vcc->aal) { 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal0: 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal0"); 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr |= CHANNEL_TYPE_RAW_CELLS; 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_ptr |= CHANNEL_TYPE_RAW_CELLS; 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal34: 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_TX, "tx_channel: aal34"); 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr |= CHANNEL_TYPE_AAL3_4; 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_ptr |= CHANNEL_TYPE_AAL3_4; 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal5: 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_ptr |= CHANNEL_TYPE_AAL5; 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_ptr |= CHANNEL_TYPE_AAL5; 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise the CRC 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->partial_crc, INITIAL_CRC); 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->rd_buf_type, rd_ptr); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->wr_buf_type, wr_ptr); 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Write the Cell Header 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Payload Type, CLP and GFC would go here if non-zero 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->cell_header, channel); 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&dev->mem_lock, flags); 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tx_channel; 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** send a frame **********/ 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_send (struct atm_vcc * atm_vcc, struct sk_buff * skb) { 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int spin_count; 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int free_buffers; 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_vcc->dev); 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_vcc * vcc = HRZ_VCC(atm_vcc); 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 channel = vcc->channel; 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 buffers_required; 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* signed for error return */ 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short tx_channel; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_TX, "hrz_send vc %x data %p len %u", 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds channel, skb->data, skb->len); 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dump_skb (">>>", channel, skb); 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc->qos.txtp.traffic_class == ATM_NONE) { 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "attempt to send on RX-only VC %x", channel); 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // don't understand this 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ATM_SKB(skb)->vcc = atm_vcc; 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb->len > atm_vcc->qos.txtp.max_sdu) { 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "sk_buff length greater than agreed max_sdu, dropping..."); 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!channel) { 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_ERR|DBG_TX, "attempt to transmit on zero (rx_)channel"); 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // where would be a better place for this? housekeeping? 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 status; 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word (dev->pci_dev, PCI_STATUS, &status); 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & PCI_STATUS_REC_MASTER_ABORT) { 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_BUS|DBG_ERR, "Clearing PCI Master Abort (and cleaning up)"); 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= ~PCI_STATUS_REC_MASTER_ABORT; 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_word (dev->pci_dev, PCI_STATUS, status); 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_bit (tx_busy, &dev->flags)) { 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (dev->tx_skb); 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_HORIZON 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* wey-hey! */ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == 1023) { 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short d = 0; 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char * s = skb->data; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*s++ == 'D') { 164966bb16de6b9a05936d1eeb20155bab008b476191Andy Shevchenko for (i = 0; i < 4; ++i) 165066bb16de6b9a05936d1eeb20155bab008b476191Andy Shevchenko d = (d << 4) | hex_to_bin(*s++); 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_INFO, "debug bitmap is now %hx", debug = d); 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // wait until TX is free and grab lock 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_hold (dev)) { 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Wait for enough space to be available in transmit buffer memory. 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // should be number of cells needed + 2 (according to hardware docs) 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // = ((framelen+8)+47) / 48 + 2 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // = (framelen+7) / 48 + 3, hmm... faster to put addition inside XXX 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffers_required = (skb->len+(ATM_AAL5_TRAILER-1)) / ATM_CELL_PAYLOAD + 3; 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // replace with timer and sleep, add dev->tx_buffers_queue (max 1 entry) 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_count = 0; 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ((free_buffers = rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF)) < buffers_required) { 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "waiting for free TX buffers, got %d of %d", 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_buffers, buffers_required); 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // what is the appropriate delay? implement a timeout? (depending on line speed?) 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // mdelay (1); 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // what happens if we kill (current_pid, SIGKILL) ? 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule(); 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++spin_count > 1000) { 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "spun out waiting for tx buffers, got %d of %d", 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_buffers, buffers_required); 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ERESTARTSYS; 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Select a channel to transmit the frame on. 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (channel == dev->last_vc) { 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "last vc hack: hit"); 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_channel = dev->tx_last; 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "last vc hack: miss"); 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Are we currently transmitting this VC on one of the channels? 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (tx_channel = 0; tx_channel < TX_CHANS; ++tx_channel) 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->tx_channel_record[tx_channel] == channel) { 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "vc already on channel: hit"); 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_channel == TX_CHANS) { 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "vc already on channel: miss"); 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Find and set up an idle channel. 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_channel = setup_idle_tx_channel (dev, vcc); 17031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_channel < 0) { 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_ERR, "failed to get channel"); 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return tx_channel; 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "got channel"); 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SELECT_TX_CHANNEL(dev, tx_channel); 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->last_vc = channel; 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_last = tx_channel; 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX, "using channel %u", tx_channel); 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_OFF(dev); 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // TX start transfer 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tx_len = skb->len; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int tx_iovcnt = skb_shinfo(skb)->nr_frags; 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // remember this so we can free it later 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_skb = skb; 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_iovcnt) { 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // scatter gather transfer 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_regions = tx_iovcnt; 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_iovec = NULL; /* @@@ needs rewritten */ 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = 0; 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)", 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data, tx_len); 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_kfree_skb (skb); 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EIO; 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // simple transfer 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_regions = 0; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_iovec = NULL; 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = tx_len; 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_addr = skb->data; 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_TX|DBG_BUS, "TX start simple transfer (addr %p, len %d)", 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->data, tx_len); 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // and do the business 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_schedule (dev, 0); 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** reset a card **********/ 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hrz_reset (const hrz_dev * dev) { 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 control_0_reg = rd_regl (dev, CONTROL_0_REG); 17611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // why not set RESET_HORIZON to one and wait for the card to 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // reassert that bit as zero? Like so: 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_0_reg = control_0_reg & RESET_HORIZON; 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, control_0_reg); 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (control_0_reg & RESET_HORIZON) 17671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control_0_reg = rd_regl (dev, CONTROL_0_REG); 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // old reset code retained: 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, control_0_reg | 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RESET_ATM | RESET_RX | RESET_TX | RESET_HOST); 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // just guessing here 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay (1000); 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, control_0_reg); 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** read the burnt in address **********/ 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17802cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void WRITE_IT_WAIT (const hrz_dev *dev, u32 ctrl) 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, ctrl); 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay (5); 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17862cf83afe902fd72ef4b211774e48ab39890fb328Denys Vlasenkostatic void CLOCK_IT (const hrz_dev *dev, u32 ctrl) 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // DI must be valid around rising SK edge 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WRITE_IT_WAIT(dev, ctrl & ~SEEPROM_SK); 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WRITE_IT_WAIT(dev, ctrl | SEEPROM_SK); 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1793977a415f2b70b5693aaa23b1a16ad57ea20a1dceDavid S. Millerstatic u16 __devinit read_bia (const hrz_dev * dev, u16 addr) 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ctrl = rd_regl (dev, CONTROL_0_REG); 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned int addr_bits = 6; 17981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned int data_bits = 16; 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 res; 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~(SEEPROM_CS | SEEPROM_SK | SEEPROM_DI); 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WRITE_IT_WAIT(dev, ctrl); 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // wake Serial EEPROM and send 110 (READ) command 18081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= (SEEPROM_CS | SEEPROM_DI); 18091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CLOCK_IT(dev, ctrl); 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= SEEPROM_DI; 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CLOCK_IT(dev, ctrl); 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~SEEPROM_DI; 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CLOCK_IT(dev, ctrl); 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<addr_bits; i++) { 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (addr & (1 << (addr_bits-1))) 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= SEEPROM_DI; 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~SEEPROM_DI; 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CLOCK_IT(dev, ctrl); 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr = addr << 1; 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we could check that we have DO = 0 here 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~SEEPROM_DI; 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 0; 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0;i<data_bits;i++) { 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = res >> 1; 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CLOCK_IT(dev, ctrl); 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rd_regl (dev, CONTROL_0_REG) & SEEPROM_DO) 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res |= (1 << (data_bits-1)); 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~(SEEPROM_SK | SEEPROM_CS); 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds WRITE_IT_WAIT(dev, ctrl); 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** initialise a card **********/ 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18490a3c4bdc1b197a7d37fc75643a68daf45fe0a7ccAl Virostatic int __devinit hrz_init (hrz_dev * dev) { 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int onefivefive; 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 chan; 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int buff_count; 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds HDW * mem; 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cell_buf * tx_desc; 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cell_buf * rx_desc; 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 ctrl; 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl = rd_regl (dev, CONTROL_0_REG); 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_INFO, "ctrl0reg is %#x", ctrl); 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds onefivefive = ctrl & ATM_LAYER_STATUS; 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (onefivefive) 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (DEV_LABEL ": Horizon Ultra (at 155.52 MBps)"); 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (DEV_LABEL ": Horizon (at 25 MBps)"); 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (":"); 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Reset the card to get everything in a known state 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" reset"); 18761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_reset (dev); 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Clear all the buffer memory 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" clearing memory"); 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (mem = (HDW *) memmap; mem < (HDW *) (memmap + 1); ++mem) 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, mem, 0); 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" tx channels"); 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // All transmit eight channels are set up as AAL5 ABR channels with 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // a 16us cell spacing. Why? 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Channel 0 gets the free buffer at 100h, channel 1 gets the free 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // buffer at 110h etc. 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (chan = 0; chan < TX_CHANS; ++chan) { 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_ch_desc * tx_desc = &memmap->tx_descs[chan]; 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cell_buf * buf = &memmap->inittxbufs[chan]; 18961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // initialise the read and write buffer pointers 18981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->rd_buf_type, BUF_PTR(buf)); 18991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->wr_buf_type, BUF_PTR(buf)); 19001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set the status of the initial buffers to empty 19021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &buf->next, BUFF_STATUS_EMPTY); 19031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Use space bufn3 at the moment for tx buffers 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" tx buffers"); 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_desc = memmap->bufn3; 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &memmap->txfreebufstart.next, BUF_PTR(tx_desc) | BUFF_STATUS_EMPTY); 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (buff_count = 0; buff_count < BUFN3_SIZE-1; buff_count++) { 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->next, BUF_PTR(tx_desc+1) | BUFF_STATUS_EMPTY); 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_desc++; 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &tx_desc->next, BUF_PTR(&memmap->txfreebufend) | BUFF_STATUS_EMPTY); 19191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise the transmit free buffer count 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, TX_FREE_BUFFER_COUNT_OFF, BUFN3_SIZE); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" rx channels"); 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise all of the receive channels to be AAL5 disabled with 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // an interrupt threshold of 0 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (chan = 0; chan < RX_CHANS; ++chan) { 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ch_desc * rx_desc = &memmap->rx_descs[chan]; 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->wr_buf_type, CHANNEL_TYPE_AAL5 | RX_CHANNEL_DISABLED); 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" rx buffers"); 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Use space bufn4 at the moment for rx buffers 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_desc = memmap->bufn4; 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &memmap->rxfreebufstart.next, BUF_PTR(rx_desc) | BUFF_STATUS_EMPTY); 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (buff_count = 0; buff_count < BUFN4_SIZE-1; buff_count++) { 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->next, BUF_PTR(rx_desc+1) | BUFF_STATUS_EMPTY); 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_desc++; 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_mem (dev, &rx_desc->next, BUF_PTR(&memmap->rxfreebufend) | BUFF_STATUS_EMPTY); 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialise the receive free buffer count 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_FREE_BUFFER_COUNT_OFF, BUFN4_SIZE); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Initialize Horizons registers 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // TX config 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, TX_CONFIG_OFF, 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ABR_ROUND_ROBIN | TX_NORMAL_OPERATION | DRVR_DRVRBAR_ENABLE); 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // RX config. Use 10-x VC bits, x VP bits, non user cells in channel 0. 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_CONFIG_OFF, 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DISCARD_UNUSED_VPI_VCI_BITS_SET | NON_USER_CELLS_IN_ONE_CHANNEL | vpi_bits); 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // RX line config 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_LINE_CONFIG_OFF, 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LOCK_DETECT_ENABLE | FREQUENCY_DETECT_ENABLE | GXTALOUT_SELECT_DIV4); 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Set the max AAL5 cell count to be just enough to contain the 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // largest AAL5 frame that the user wants to receive 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, MAX_AAL5_CELL_COUNT_OFF, 19706a19309db0a02d821494f4df754046c85a230627Julia Lawall DIV_ROUND_UP(max_rx_size + ATM_AAL5_TRAILER, ATM_CELL_PAYLOAD)); 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Enable receive 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE); 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" control"); 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Drive the OE of the LEDs then turn the green LED on 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= GREEN_LED_OE | YELLOW_LED_OE | GREEN_LED | YELLOW_LED; 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, ctrl); 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Test for a 155-capable card 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (onefivefive) { 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Select 155 mode... make this a choice (or: how do we detect 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // external line speed and switch?) 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl |= ATM_LAYER_SELECT; 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, CONTROL_0_REG, ctrl); 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // test SUNI-lite vs SAMBA 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Register 0x00 in the SUNI will have some of bits 3-7 set, and 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // they will always be zero for the SAMBA. Ha! Bloody hardware 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // engineers. It'll never work. 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rd_framer (dev, 0) & 0x00f0) { 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // SUNI 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" SUNI"); 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Reset, just in case 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0x00, 0x0080); 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0x00, 0x0000); 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Configure transmit FIFO 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0x63, rd_framer (dev, 0x63) | 0x0002); 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Set line timed mode 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0x05, rd_framer (dev, 0x05) | 0x0001); 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // SAMBA 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" SAMBA"); 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Reset, just in case 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0, rd_framer (dev, 0) | 0x0001); 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0, rd_framer (dev, 0) &~ 0x0001); 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Turn off diagnostic loopback and enable line-timed mode 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 0, 0x0002); 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Turn on transmit outputs 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_framer (dev, 2, 0x0B80); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Select 25 mode 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ctrl &= ~ATM_LAYER_SELECT; 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Madge B154 setup 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // none required? 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" LEDs"); 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GREEN_LED_ON(dev); 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds YELLOW_LED_ON(dev); 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" ESI="); 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 b = 0; 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 * esi = dev->atm_dev->esi; 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // in the card I have, EEPROM 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // addresses 0, 1, 2 contain 0 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // addresess 5, 6 etc. contain ffff 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // NB: Madge prefix is 00 00 f6 (which is 00 00 6f in Ethernet bit order) 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // the read_bia routine gets the BIA in Ethernet bit order 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i < ESI_LEN; ++i) { 20491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i % 2 == 0) 20501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b = read_bia (dev, i/2 + 2); 20511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 20521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b = b >> 8; 20531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds esi[i] = b & 0xFF; 20541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%02x", esi[i]); 20551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Enable RX_Q and ?X_COMPLETE interrupts only 20591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wr_regl (dev, INT_ENABLE_REG_OFF, INTERESTING_INTERRUPTS); 20601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (" IRQ on"); 20611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (".\n"); 20631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return onefivefive; 20651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** check max_sdu **********/ 20681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int check_max_sdu (hrz_aal aal, struct atm_trafprm * tp, unsigned int max_frame_size) { 20701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_QOS, "check_max_sdu"); 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (aal) { 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal0: 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(tp->max_sdu)) { 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "defaulting max_sdu"); 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->max_sdu = ATM_AAL0_SDU; 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (tp->max_sdu != ATM_AAL0_SDU) { 20781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_ERR, "rejecting max_sdu"); 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal34: 20831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->max_sdu == 0 || tp->max_sdu > ATM_MAX_AAL34_PDU) { 20841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); 20851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->max_sdu = ATM_MAX_AAL34_PDU; 20861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case aal5: 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->max_sdu == 0 || tp->max_sdu > max_frame_size) { 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "%sing max_sdu", tp->max_sdu ? "capp" : "default"); 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->max_sdu = max_frame_size; 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 20961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** check pcr **********/ 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// something like this should be part of ATM Linux 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int atm_pcr_check (struct atm_trafprm * tp, unsigned int pcr) { 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we are assuming non-UBR, and non-special values of pcr 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->min_pcr == ATM_MAX_PCR) 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "luser gave min_pcr = ATM_MAX_PCR"); 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (tp->min_pcr < 0) 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "luser gave negative min_pcr"); 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (tp->min_pcr && tp->min_pcr > pcr) 21081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "pcr less than min_pcr"); 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // !! max_pcr = UNSPEC (0) is equivalent to max_pcr = MAX (-1) 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // easier to #define ATM_MAX_PCR 0 and have all rates unsigned? 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // [this would get rid of next two conditionals] 21131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((0) && tp->max_pcr == ATM_MAX_PCR) 21141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "luser gave max_pcr = ATM_MAX_PCR"); 21151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((tp->max_pcr != ATM_MAX_PCR) && tp->max_pcr < 0) 21161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "luser gave negative max_pcr"); 21171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (tp->max_pcr && tp->max_pcr != ATM_MAX_PCR && tp->max_pcr < pcr) 21181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "pcr greater than max_pcr"); 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // each limit unspecified or not violated 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "xBR(pcr) OK"); 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "pcr=%u, tp: min_pcr=%d, pcr=%d, max_pcr=%d", 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr, tp->min_pcr, tp->pcr, tp->max_pcr); 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** open VC **********/ 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_open (struct atm_vcc *atm_vcc) 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int error; 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 channel; 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_qos * qos; 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_trafprm * txtp; 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct atm_trafprm * rxtp; 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_vcc->dev); 21411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_vcc vcc; 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_vcc * vccp; // allocated late 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short vpi = atm_vcc->vpi; 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int vci = atm_vcc->vci; 21451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_VCC, "hrz_open %x %x", vpi, vci); 21461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef ATM_VPI_UNSPEC 21481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // UNSPEC is deprecated, remove this code eventually 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) { 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_WARNING, "rejecting open with unspecified VPI/VCI (deprecated)"); 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = vpivci_to_channel (&channel, vpi, vci); 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 21571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_WARN|DBG_VCC, "VPI/VCI out of range: %hd/%d", vpi, vci); 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.channel = channel; 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // max speed for the moment 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_rate = 0x0; 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qos = &atm_vcc->qos; 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // check AAL and remember it 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (qos->aal) { 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_AAL0: 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we would if it were 48 bytes and not 52! 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "AAL0"); 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.aal = aal0; 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_AAL34: 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we would if I knew how do the SAR! 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "AAL3/4"); 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.aal = aal34; 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_AAL5: 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "AAL5"); 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.aal = aal5; 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "Bad AAL!"); 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // TX traffic parameters 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // there are two, interrelated problems here: 1. the reservation of 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // PCR is not a binary choice, we are given bounds and/or a 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // desirable value; 2. the device is only capable of certain values, 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // most of which are not integers. It is almost certainly acceptable 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // to be off by a maximum of 1 to 10 cps. 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Pragmatic choice: always store an integral PCR as that which has 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // been allocated, even if we allocate a little (or a lot) less, 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // after rounding. The actual allocation depends on what we can 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // manage with our rate selection algorithm. The rate selection 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // algorithm is given an integral PCR and a tolerance and told 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // whether it should round the value up or down if the tolerance is 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // exceeded; it returns: a) the actual rate selected (rounded up to 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // the nearest integer), b) a bit pattern to feed to the timer 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // register, and c) a failure value if no applicable rate exists. 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Part of the job is done by atm_pcr_goal which gives us a PCR 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // specification which says: EITHER grab the maximum available PCR 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (and perhaps a lower bound which we musn't pass), OR grab this 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // amount, rounding down if you have to (and perhaps a lower bound 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // which we musn't pass) OR grab this amount, rounding up if you 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // have to (and perhaps an upper bound which we musn't pass). If any 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // bounds ARE passed we fail. Note that rounding is only rounding to 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // match device limitations, we do not round down to satisfy 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // bandwidth availability even if this would not violate any given 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // lower bound. 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Note: telephony = 64kb/s = 48 byte cell payload @ 500/3 cells/s 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // (say) so this is not even a binary fixpoint cell rate (but this 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // device can do it). To avoid this sort of hassle we use a 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // tolerance parameter (currently fixed at 10 cps). 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "TX:"); 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds txtp = &qos->txtp; 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set up defaults for no traffic 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_rate = 0; 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // who knows what would actually happen if you try and send on this? 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_xbr_bits = IDLE_RATE_TYPE; 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_pcr_bits = CLOCK_DISABLE; 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_scr_bits = CLOCK_DISABLE; 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_bucket_bits = 0; 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (txtp->traffic_class != ATM_NONE) { 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = check_max_sdu (vcc.aal, txtp, max_tx_size); 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "TX max_sdu check failed"); 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (txtp->traffic_class) { 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_UBR: { 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // we take "the PCR" as a rate-cap 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not reserved 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_rate = 0; 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, NULL); 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_xbr_bits = ABR_RATE_TYPE; 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_ABR: { 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // reserve min, allow up to max 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_rate = 0; // ? 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds make_rate (dev, 1<<30, round_nearest, &vcc.tx_pcr_bits, 0); 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_xbr_bits = ABR_RATE_TYPE; 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_CBR: { 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pcr = atm_pcr_goal (txtp); 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rounding r; 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pcr) { 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // down vs. up, remaining bandwidth vs. unlimited bandwidth!! 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // should really have: once someone gets unlimited bandwidth 22681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // that no more non-UBR channels can be opened until the 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // unlimited one closes?? For the moment, round_down means 22701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // greedy people actually get something and not nothing 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = round_down; 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // slight race (no locking) here so we may get -EAGAIN 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // later; the greedy bastards would deserve it :) 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = dev->tx_avail; 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (pcr < 0) { 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = round_down; 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = -pcr; 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r = round_up; 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = make_rate_with_tolerance (dev, pcr, r, 10, 22831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &vcc.tx_pcr_bits, &vcc.tx_rate); 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "could not make rate from TX PCR"); 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not really clear what further checking is needed 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = atm_pcr_check (txtp, vcc.tx_rate); 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "TX PCR failed consistency check"); 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_xbr_bits = CBR_RATE_TYPE; 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_VBR: { 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pcr = atm_pcr_goal (txtp); 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // int scr = atm_scr_goal (txtp); 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int scr = pcr/2; // just for fun 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int mbs = 60; // just for fun 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rounding pr; 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rounding sr; 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int bucket; 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pcr) { 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr = round_nearest; 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = 1<<30; 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (pcr < 0) { 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr = round_down; 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = -pcr; 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pr = round_up; 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = make_rate_with_tolerance (dev, pcr, pr, 10, 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &vcc.tx_pcr_bits, 0); 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!scr) { 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // see comments for PCR with CBR above 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sr = round_down; 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // slight race (no locking) here so we may get -EAGAIN 23211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // later; the greedy bastards would deserve it :) 23221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "snatching all remaining TX bandwidth"); 23231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr = dev->tx_avail; 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (scr < 0) { 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sr = round_down; 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr = -scr; 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sr = round_up; 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = make_rate_with_tolerance (dev, scr, sr, 10, 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &vcc.tx_scr_bits, &vcc.tx_rate); 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "could not make rate from TX SCR"); 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not really clear what further checking is needed 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // error = atm_scr_check (txtp, vcc.tx_rate); 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "TX SCR failed consistency check"); 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // bucket calculations (from a piece of paper...) cell bucket 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // capacity must be largest integer smaller than m(p-s)/p + 1 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // where m = max burst size, p = pcr, s = scr 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bucket = mbs*(pcr-scr)/pcr; 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bucket*pcr != mbs*(pcr-scr)) 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bucket += 1; 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bucket > BUCKET_MAX_SIZE) { 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "shrinking bucket from %u to %u", 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bucket, BUCKET_MAX_SIZE); 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bucket = BUCKET_MAX_SIZE; 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_xbr_bits = VBR_RATE_TYPE; 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_bucket_bits = bucket; 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: { 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "unsupported TX traffic class"); 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // RX traffic parameters 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "RX:"); 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rxtp = &qos->rxtp; 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // set up defaults for no traffic 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.rx_rate = 0; 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rxtp->traffic_class != ATM_NONE) { 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = check_max_sdu (vcc.aal, rxtp, max_rx_size); 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "RX max_sdu check failed"); 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (rxtp->traffic_class) { 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_UBR: { 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not reserved 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_ABR: { 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // reserve min 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.rx_rate = 0; // ? 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_CBR: { 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pcr = atm_pcr_goal (rxtp); 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pcr) { 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // slight race (no locking) here so we may get -EAGAIN 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // later; the greedy bastards would deserve it :) 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = dev->rx_avail; 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (pcr < 0) { 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcr = -pcr; 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.rx_rate = pcr; 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not really clear what further checking is needed 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = atm_pcr_check (rxtp, vcc.rx_rate); 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "RX PCR failed consistency check"); 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ATM_VBR: { 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // int scr = atm_scr_goal (rxtp); 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int scr = 1<<16; // just for fun 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!scr) { 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // slight race (no locking) here so we may get -EAGAIN 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // later; the greedy bastards would deserve it :) 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "snatching all remaining RX bandwidth"); 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr = dev->rx_avail; 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (scr < 0) { 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr = -scr; 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.rx_rate = scr; 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // not really clear what further checking is needed 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // error = atm_scr_check (rxtp, vcc.rx_rate); 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "RX SCR failed consistency check"); 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: { 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "unsupported RX traffic class"); 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // late abort useful for diagnostics 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc.aal != aal5) { 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "AAL not supported"); 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // get space for our vcc stuff and copy parameters into it 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL); 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!vccp) { 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "out of memory!"); 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *vccp = vcc; 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // clear error and grab cell rate resource lock 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = 0; 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dev->rate_lock); 24601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc.tx_rate > dev->tx_avail) { 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "not enough TX PCR left"); 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EAGAIN; 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vcc.rx_rate > dev->rx_avail) { 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS, "not enough RX PCR left"); 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EAGAIN; 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!error) { 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // really consume cell rates 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_avail -= vcc.tx_rate; 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_avail -= vcc.rx_rate; 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "reserving %u TX PCR and %u RX PCR", 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc.tx_rate, vcc.rx_rate); 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // release lock and exit on error 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dev->rate_lock); 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources"); 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (vccp); 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // this is "immediately before allocating the connection identifier 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // in hardware" - so long as the next call does not fail :) 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(ATM_VF_ADDR,&atm_vcc->flags); 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // any errors here are very serious and should never occur 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rxtp->traffic_class != ATM_NONE) { 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->rxer[channel]) { 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_ERR|DBG_VCC, "VC already open for RX"); 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = -EBUSY; 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!error) 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds error = hrz_open_rx (dev, channel); 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (error) { 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (vccp); 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return error; 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // this link allows RX frames through 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rxer[channel] = atm_vcc; 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // success, set elements of atm_vcc 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atm_vcc->dev_data = (void *) vccp; 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // indicate readiness 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(ATM_VF_READY,&atm_vcc->flags); 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** close VC **********/ 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hrz_close (struct atm_vcc * atm_vcc) { 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_vcc->dev); 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_vcc * vcc = HRZ_VCC(atm_vcc); 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 channel = vcc->channel; 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_VCC|DBG_FLOW, "hrz_close"); 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // indicate unreadiness 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(ATM_VF_READY,&atm_vcc->flags); 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) { 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // let any TX on this channel that has started complete 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // no restart, just keep trying 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (tx_hold (dev)) 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // remove record of any tx_channel having been setup for this channel 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < TX_CHANS; ++i) 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->tx_channel_record[i] == channel) { 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_channel_record[i] = -1; 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->last_vc == channel) 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_last = -1; 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_release (dev); 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc->qos.rxtp.traffic_class != ATM_NONE) { 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // disable RXing - it tries quite hard 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_close_rx (dev, channel); 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // forget the vcc - no more skbs will be pushed 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (atm_vcc != dev->rxer[channel]) 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "%s atm_vcc=%p rxer[channel]=%p", 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "arghhh! we're going to die!", 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atm_vcc, dev->rxer[channel]); 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rxer[channel] = NULL; 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // atomically release our rate reservation 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&dev->rate_lock); 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_QOS|DBG_VCC, "releasing %u TX PCR and %u RX PCR", 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vcc->tx_rate, vcc->rx_rate); 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_avail += vcc->tx_rate; 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_avail += vcc->rx_rate; 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&dev->rate_lock); 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // free our structure 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (vcc); 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // say the VPI/VCI is free again 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_bit(ATM_VF_ADDR,&atm_vcc->flags); 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_getsockopt (struct atm_vcc * atm_vcc, int level, int optname, 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void *optval, int optlen) { 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_vcc->dev); 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_VCC, "hrz_getsockopt"); 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (level) { 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SOL_SOCKET: 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (optname) { 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// case SO_BCTXOPT: 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// break; 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// case SO_BCRXOPT: 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// break; 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOPROTOOPT; 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_setsockopt (struct atm_vcc * atm_vcc, int level, int optname, 2593b7058842c940ad2c08dd829b21e5c92ebe3b8758David S. Miller void *optval, unsigned int optlen) { 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_vcc->dev); 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW|DBG_VCC, "hrz_setsockopt"); 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (level) { 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SOL_SOCKET: 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (optname) { 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// case SO_BCTXOPT: 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// break; 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// case SO_BCRXOPT: 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// break; 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOPROTOOPT; 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_ioctl (struct atm_dev * atm_dev, unsigned int cmd, void *arg) { 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_dev); 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_ioctl"); 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned char hrz_phy_get (struct atm_dev * atm_dev, unsigned long addr) { 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_dev); 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_phy_get"); 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hrz_phy_put (struct atm_dev * atm_dev, unsigned char value, 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long addr) { 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_dev); 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_phy_put"); 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_change_qos (struct atm_vcc * atm_vcc, struct atm_qos *qos, int flgs) { 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(vcc->dev); 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_change_qos"); 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** proc file contents **********/ 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int hrz_proc_read (struct atm_dev * atm_dev, loff_t * pos, char * page) { 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev = HRZ_DEV(atm_dev); 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int left = *pos; 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_proc_read"); 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* more diagnostics here? */ 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!left--) { 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int count = sprintf (page, "vbr buckets:"); 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < TX_CHANS; ++i) 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count += sprintf (page, " %u/%u", 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds query_tx_channel_config (dev, i, BUCKET_FULLNESS_ACCESS), 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds query_tx_channel_config (dev, i, BUCKET_CAPACITY_ACCESS)); 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count += sprintf (page+count, ".\n"); 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!left--) 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf (page, 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cells: TX %lu, RX %lu, HEC errors %lu, unassigned %lu.\n", 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_cell_count, dev->rx_cell_count, 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hec_error_count, dev->unassigned_cell_count); 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!left--) 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf (page, 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "free cell buffers: TX %hu, RX %hu+%hu.\n", 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_regw (dev, TX_FREE_BUFFER_COUNT_OFF), 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_regw (dev, RX_FREE_BUFFER_COUNT_OFF), 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->noof_spare_buffers); 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!left--) 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf (page, 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cps remaining: TX %u, RX %u\n", 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_avail, dev->rx_avail); 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct atmdev_ops hrz_ops = { 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = hrz_open, 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .close = hrz_close, 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .send = hrz_send, 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_read = hrz_proc_read, 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 26921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev * dev; 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // adapter slot free, read resources from PCI configuration space 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 iobase = pci_resource_start (pci_dev, 0); 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 * membase = bus_to_virt (pci_resource_start (pci_dev, 1)); 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int irq; 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char lat; 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "hrz_probe"); 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_enable_device(pci_dev)) 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX DEV_LABEL is a guess */ 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(iobase, HRZ_IO_EXTENT, DEV_LABEL)) { 2708aac725cf1649d593a13be1edc99ed489f8050a99Jiri Slaby err = -EINVAL; 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_disable; 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27120c1cca1d8e0d58775dad43374f925e6cddf1bebcOm Narasimhan dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL); 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) { 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // perhaps we should be nice: deregister all adapters and abort? 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_ERR, "out of memory"); 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_release; 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_set_drvdata(pci_dev, dev); 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // grab IRQ and install handler - move this someplace more sensible 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = pci_dev->irq; 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(irq, 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds interrupt_handler, 2726dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner IRQF_SHARED, /* irqflags guess */ 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DEV_LABEL, /* name guess */ 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev)) { 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_WARN, "request IRQ failed!"); 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_INFO, "found Madge ATM adapter (hrz) at: IO %x, IRQ %u, MEM %p", 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobase, irq, membase); 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2737d9ca676bcb26e1fdff9265a3e70f697cd381c889Dan Williams dev->atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &hrz_ops, -1, 2738d9ca676bcb26e1fdff9265a3e70f697cd381c889Dan Williams NULL); 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(dev->atm_dev)) { 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_ERR, "failed to register Madge ATM adapter"); 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EINVAL; 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free_irq; 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p", 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->atm_dev->number, dev, dev->atm_dev); 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->atm_dev->dev_data = (void *) dev; 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->pci_dev = pci_dev; 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // enable bus master accesses 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_set_master(pci_dev); 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // frobnicate latency (upwards, usually) 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat); 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pci_lat) { 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_INFO, "%s PCI latency timer from %hu to %hu", 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "changing", lat, pci_lat); 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat); 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (lat < MIN_PCI_LATENCY) { 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK(KERN_INFO, "%s PCI latency timer from %hu to %hu", 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "increasing", lat, MIN_PCI_LATENCY); 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY); 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->iobase = iobase; 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->membase = membase; 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_q_entry = dev->rx_q_reset = &memmap->rx_q_entries[0]; 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_q_wrap = &memmap->rx_q_entries[RX_CHANS-1]; 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // these next three are performance hacks 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->last_vc = -1; 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_last = -1; 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_idle = 0; 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_regions = 0; 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_bytes = 0; 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_skb = NULL; 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_iovec = NULL; 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_cell_count = 0; 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_cell_count = 0; 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->hec_error_count = 0; 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->unassigned_cell_count = 0; 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->noof_spare_buffers = 0; 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int i; 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < TX_CHANS; ++i) 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_channel_record[i] = -1; 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags = 0; 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Allocate cell rates and remember ASIC version 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Fibre: ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Copper: (WRONG) we want 6 into the above, close to 25Mb/s 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // Copper: (plagarise!) 25600000/8/270*260/53 - n/53 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hrz_init(dev)) { 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // to be really pedantic, this should be ATM_OC3c_PCR 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_avail = ATM_OC3_PCR; 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_avail = ATM_OC3_PCR; 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(ultra, &dev->flags); // NOT "|= ultra" ! 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_avail = ((25600000/8)*26)/(27*53); 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->rx_avail = ((25600000/8)*26)/(27*53); 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_WARN, "Buggy ASIC: no TX bus-mastering."); 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // rate changes spinlock 28141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&dev->rate_lock); 28151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // on-board memory access spinlock; we want atomic reads and 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // writes to adapter memory (handles IRQ and SMP) 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&dev->mem_lock); 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_waitqueue_head(&dev->tx_queue); 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // vpi in 0..4, vci in 6..10 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->atm_dev->ci_range.vpi_bits = vpi_bits; 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->atm_dev->ci_range.vci_bits = 10-vpi_bits; 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&dev->housekeeping); 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->housekeeping.function = do_housekeeping; 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->housekeeping.data = (unsigned long) dev; 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mod_timer(&dev->housekeeping, jiffies); 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free_irq: 28351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dev); 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_release: 28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(iobase, HRZ_IO_EXTENT); 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_disable: 28411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(pci_dev); 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit hrz_remove_one(struct pci_dev *pci_dev) 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_dev *dev; 28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = pci_get_drvdata(pci_dev); 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD(DBG_INFO, "closing %p (atm_dev = %p)", dev, dev->atm_dev); 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&dev->housekeeping); 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_reset(dev); 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds atm_dev_deregister(dev->atm_dev); 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->iobase, HRZ_IO_EXTENT); 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dev); 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_disable_device(pci_dev); 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init hrz_check_args (void) { 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_HORIZON 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_NOTICE, "debug bitmap is %hx", debug &= DBG_MASK); 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (debug) 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_NOTICE, "no debug support in this image"); 28681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 28691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (vpi_bits > HRZ_MAX_VPI) 28711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "vpi_bits has been limited to %hu", 28721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vpi_bits = HRZ_MAX_VPI); 28731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max_tx_size < 0 || max_tx_size > TX_AAL5_LIMIT) 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_NOTICE, "max_tx_size has been limited to %hu", 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_tx_size = TX_AAL5_LIMIT); 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (max_rx_size < 0 || max_rx_size > RX_AAL5_LIMIT) 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_NOTICE, "max_rx_size has been limited to %hu", 28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds max_rx_size = RX_AAL5_LIMIT); 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR(maintainer_string); 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION(description_string); 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, ushort, 0644); 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(vpi_bits, ushort, 0); 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(max_tx_size, int, 0); 28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(max_rx_size, int, 0); 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(pci_lat, byte, 0); 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "debug bitmap, see .h file"); 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(vpi_bits, "number of bits (0..4) to allocate to VPIs"); 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_tx_size, "maximum size of TX AAL5 frames"); 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(max_rx_size, "maximum size of RX AAL5 frames"); 28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(pci_lat, "PCI latency in bus cycles"); 28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id hrz_pci_tbl[] = { 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { PCI_VENDOR_ID_MADGE, PCI_DEVICE_ID_MADGE_HORIZON, PCI_ANY_ID, PCI_ANY_ID, 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0, 0, 0 }, 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, } 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, hrz_pci_tbl); 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver hrz_driver = { 29081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "horizon", 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = hrz_probe, 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p(hrz_remove_one), 29111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = hrz_pci_tbl, 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** module entry **********/ 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init hrz_module_init (void) { 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // sanity check - cast is needed since printk does not support %Zu 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sizeof(struct MEMMAP) != 128*1024/4) { 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK (KERN_ERR, "Fix struct MEMMAP (is %lu fakewords).", 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long) sizeof(struct MEMMAP)); 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_version(); 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // check arguments 29271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hrz_check_args(); 29281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds // get the juice 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pci_register_driver(&hrz_driver); 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/********** module exit **********/ 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit hrz_module_exit (void) { 29361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTD (DBG_FLOW, "cleanup_module"); 2937b45eccdb51c102e3c5ff9eaecc36200ab2eb09c0Tobias Klauser 2938b45eccdb51c102e3c5ff9eaecc36200ab2eb09c0Tobias Klauser pci_unregister_driver(&hrz_driver); 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(hrz_module_init); 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(hrz_module_exit); 2943