From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CDCE819D092; Tue, 21 Apr 2026 02:19:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776737988; cv=none; b=r8iqUOui/p90/pE951wUWKUukuOokobXMxsTzPSQJb+PTiligwVdPMZW4r3IMPFNB20CD535gnxKDpj/ssfscVzS8LNYR/KPH0ZqfjEPpwhSTcHoblNgd840du4Xhg5rYN40GFMX+oHQ2F7EDGjbs5gWNYOcxByH0EGysaeOWB4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776737988; c=relaxed/simple; bh=oyCOntGA5kaGyJUcflW/913yfBHTfkgh5wXF+JiOas4=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=fAraPIeGjxVIAo8PGby+gNbBLIAh9fCKqOu0+R4cAToMQMVJSk4l1bOwCG93dUZilAe0D5Yck042+yMbODxZC0Fr57K3OvNp52OOiLbstzzBFQFX5T/HiFbmTFyGGPKSmMu3tULnOwMUxsuCV9YOa9cuP0Ihuh5ce7UNWTKQ5jw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gqThTMPS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gqThTMPS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 65920C19425; Tue, 21 Apr 2026 02:19:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1776737987; bh=oyCOntGA5kaGyJUcflW/913yfBHTfkgh5wXF+JiOas4=; h=From:To:Cc:Subject:Date:From; b=gqThTMPSY4pRkuBoG8sTW/W+mZTIzK3CN+fV6J6+IcKFUbEMFNyaA6le9fSMalOCT fi35dB7mMgcM1oys2forLhpdkyiveMPbiX5O6zOcLFa9wAh0VWfc/fG6Dd5pwr7oAJ RYQCOElls0vSi6PnoHGQVPQqbIwf3+HePcvX4XSCItvVQxqxkFbD2yJBk8AtzlFk0e DdHzb58MQQzu4vUXkTfOqzV3x1OTHbTMjqQLrHfPRwyrndUOiIvGu+pcalPiB5bL3M vkfO1tdstmrrS8mqFynhD2SFMeeb3Qo8Kp/nNfNik3haM3hUvrJFfHvRd3ctUpak82 BMTPAGg5FmyYw== From: Jakub Kicinski To: davem@davemloft.net Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com, andrew+netdev@lunn.ch, horms@kernel.org, Jakub Kicinski , corbet@lwn.net, skhan@linuxfoundation.org, linux@armlinux.org.uk, tsbogend@alpha.franken.de, maddy@linux.ibm.com, mpe@ellerman.id.au, npiggin@gmail.com, chleroy@kernel.org, 3chas3@gmail.com, razor@blackwall.org, idosch@nvidia.com, jani.nikula@intel.com, mchehab+huawei@kernel.org, tytso@mit.edu, herbert@gondor.apana.org.au, geert@linux-m68k.org, ebiggers@kernel.org, johannes.berg@intel.com, jonathan.cameron@huawei.com, kees@kernel.org, kuniyu@google.com, fourier.thomas@gmail.com, andriy.shevchenko@intel.com, rdunlap@infradead.org, akpm@linux-foundation.org, linux-doc@vger.kernel.org, linux-mips@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, bridge@lists.linux.dev Subject: [PATCH net-deletions] net: remove unused ATM protocols and legacy ATM device drivers Date: Mon, 20 Apr 2026 19:19:42 -0700 Message-ID: <20260421021943.1295109-1-kuba@kernel.org> X-Mailer: git-send-email 2.53.0 Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the ATM protocol modules and PCI/SBUS ATM device drivers that are no longer in active use. The ATM core protocol stack, PPPoATM, and USB DSL modem drivers (drivers/usb/atm/) are retained in-tree to maintain PPP over ATM (PPPoA) support for DSL connections. Removed ATM protocol modules: - net/atm/clip.c - Classical IP over ATM (RFC 2225) - net/atm/br2684.c - RFC 2684 bridged protocols - net/atm/lec.c - LAN Emulation Client (LANE) - net/atm/mpc.c, mpoa_caches.c, mpoa_proc.c - Multi-Protocol Over ATM Removed PCI/SBUS ATM device drivers (drivers/atm/): - adummy, atmtcp - software/testing ATM devices - eni - Efficient Networks ENI155P (OC-3, ~1995) - fore200e - FORE Systems 200E PCI/SBUS (OC-3, ~1999) - he - ForeRunner HE (OC-3/OC-12, ~2000) - idt77105 - IDT 77105 25 Mbps ATM PHY - idt77252 - IDT 77252 NICStAR II (OC-3, ~2000) - iphase - Interphase ATM PCI (OC-3/DS3/E3) - lanai - Efficient Networks Speedstream 3010 - nicstar - IDT 77201 NICStAR (155/25 Mbps, ~1999) - solos-pci - Traverse Technologies ADSL2+ PCI (defunct vendor) - suni - PMC S/UNI SONET PHY library Also clean up references in: - net/bridge/ - remove ATM LANE hook (br_fdb_test_addr_hook, br_fdb_test_addr) - net/core/dev.c - remove br_fdb_test_addr_hook export - defconfig files - remove ATM driver config options The removed code is moved to an out-of-tree module package (mod-orphan). Signed-off-by: Jakub Kicinski --- CC: corbet@lwn.net CC: skhan@linuxfoundation.org CC: linux@armlinux.org.uk CC: tsbogend@alpha.franken.de CC: maddy@linux.ibm.com CC: mpe@ellerman.id.au CC: npiggin@gmail.com CC: chleroy@kernel.org CC: 3chas3@gmail.com CC: razor@blackwall.org CC: idosch@nvidia.com CC: jani.nikula@intel.com CC: mchehab+huawei@kernel.org CC: tytso@mit.edu CC: herbert@gondor.apana.org.au CC: geert@linux-m68k.org CC: ebiggers@kernel.org CC: johannes.berg@intel.com CC: jonathan.cameron@huawei.com CC: kees@kernel.org CC: kuniyu@google.com CC: fourier.thomas@gmail.com CC: andriy.shevchenko@intel.com CC: rdunlap@infradead.org CC: akpm@linux-foundation.org CC: linux-doc@vger.kernel.org CC: linux-mips@vger.kernel.org CC: linuxppc-dev@lists.ozlabs.org CC: bridge@lists.linux.dev --- MAINTAINERS | 3 +- Documentation/.renames.txt | 2 - .../device_drivers/atm/fore200e.rst | 66 - .../networking/device_drivers/atm/index.rst | 2 - .../networking/device_drivers/atm/iphase.rst | 193 - drivers/atm/Kconfig | 325 -- drivers/net/Kconfig | 2 - net/atm/Kconfig | 58 - drivers/Makefile | 1 - drivers/atm/Makefile | 32 - net/atm/Makefile | 8 +- drivers/atm/eni.h | 136 - drivers/atm/fore200e.h | 973 ----- drivers/atm/he.h | 845 ---- drivers/atm/idt77105.h | 92 - drivers/atm/idt77252.h | 816 ---- drivers/atm/idt77252_tables.h | 781 ---- drivers/atm/iphase.h | 1452 ------- drivers/atm/midway.h | 266 -- drivers/atm/nicstar.h | 759 ---- drivers/atm/suni.h | 242 -- drivers/atm/tonga.h | 21 - drivers/atm/zeprom.h | 35 - net/atm/lec.h | 155 - net/atm/lec_arpc.h | 97 - net/atm/mpc.h | 65 - net/atm/mpoa_caches.h | 99 - net/bridge/br_private.h | 4 - drivers/atm/adummy.c | 202 - drivers/atm/atmtcp.c | 513 --- drivers/atm/eni.c | 2321 ---------- drivers/atm/fore200e.c | 3012 ------------- drivers/atm/he.c | 2861 ------------- drivers/atm/idt77105.c | 376 -- drivers/atm/idt77252.c | 3797 ----------------- drivers/atm/iphase.c | 3283 -------------- drivers/atm/lanai.c | 2603 ----------- drivers/atm/nicstar.c | 2759 ------------ drivers/atm/nicstarmac.c | 244 -- drivers/atm/solos-attrlist.c | 83 - drivers/atm/solos-pci.c | 1496 ------- drivers/atm/suni.c | 391 -- net/atm/br2684.c | 872 ---- net/atm/clip.c | 960 ----- net/atm/lec.c | 2274 ---------- net/atm/mpc.c | 1538 ------- net/atm/mpoa_caches.c | 565 --- net/atm/mpoa_proc.c | 307 -- net/bridge/br.c | 7 - net/bridge/br_fdb.c | 29 - net/core/dev.c | 7 - arch/arm/configs/ixp4xx_defconfig | 5 - arch/mips/configs/gpr_defconfig | 13 - arch/mips/configs/mtx1_defconfig | 13 - arch/powerpc/configs/ppc6xx_defconfig | 9 - drivers/atm/.gitignore | 5 - drivers/atm/nicstarmac.copyright | 61 - 57 files changed, 3 insertions(+), 38133 deletions(-) delete mode 100644 Documentation/networking/device_drivers/atm/fore200e.rst delete mode 100644 Documentation/networking/device_drivers/atm/iphase.rst delete mode 100644 drivers/atm/Kconfig delete mode 100644 drivers/atm/Makefile delete mode 100644 drivers/atm/eni.h delete mode 100644 drivers/atm/fore200e.h delete mode 100644 drivers/atm/he.h delete mode 100644 drivers/atm/idt77105.h delete mode 100644 drivers/atm/idt77252.h delete mode 100644 drivers/atm/idt77252_tables.h delete mode 100644 drivers/atm/iphase.h delete mode 100644 drivers/atm/midway.h delete mode 100644 drivers/atm/nicstar.h delete mode 100644 drivers/atm/suni.h delete mode 100644 drivers/atm/tonga.h delete mode 100644 drivers/atm/zeprom.h delete mode 100644 net/atm/lec.h delete mode 100644 net/atm/lec_arpc.h delete mode 100644 net/atm/mpc.h delete mode 100644 net/atm/mpoa_caches.h delete mode 100644 drivers/atm/adummy.c delete mode 100644 drivers/atm/atmtcp.c delete mode 100644 drivers/atm/eni.c delete mode 100644 drivers/atm/fore200e.c delete mode 100644 drivers/atm/he.c delete mode 100644 drivers/atm/idt77105.c delete mode 100644 drivers/atm/idt77252.c delete mode 100644 drivers/atm/iphase.c delete mode 100644 drivers/atm/lanai.c delete mode 100644 drivers/atm/nicstar.c delete mode 100644 drivers/atm/nicstarmac.c delete mode 100644 drivers/atm/solos-attrlist.c delete mode 100644 drivers/atm/solos-pci.c delete mode 100644 drivers/atm/suni.c delete mode 100644 net/atm/br2684.c delete mode 100644 net/atm/clip.c delete mode 100644 net/atm/lec.c delete mode 100644 net/atm/mpc.c delete mode 100644 net/atm/mpoa_caches.c delete mode 100644 net/atm/mpoa_proc.c delete mode 100644 drivers/atm/.gitignore delete mode 100644 drivers/atm/nicstarmac.copyright diff --git a/MAINTAINERS b/MAINTAINERS index 867ca44422d8..cfcf422dd40a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4150,11 +4150,12 @@ L: linux-atm-general@lists.sourceforge.net (moderated for non-subscribers) L: netdev@vger.kernel.org S: Maintained W: http://linux-atm.sourceforge.net -F: drivers/atm/ +F: drivers/usb/atm/ F: include/linux/atm* F: include/linux/sonet.h F: include/uapi/linux/atm* F: include/uapi/linux/sonet.h +F: net/atm/ ATMEL MACB ETHERNET DRIVER M: Nicolas Ferre diff --git a/Documentation/.renames.txt b/Documentation/.renames.txt index e5f2f7447914..df4db1121995 100644 --- a/Documentation/.renames.txt +++ b/Documentation/.renames.txt @@ -835,14 +835,12 @@ networking/e100 networking/device_drivers/ethernet/intel/e100 networking/e1000 networking/device_drivers/ethernet/intel/e1000 networking/e1000e networking/device_drivers/ethernet/intel/e1000e networking/fm10k networking/device_drivers/ethernet/intel/fm10k -networking/fore200e networking/device_drivers/atm/fore200e networking/hinic networking/device_drivers/ethernet/huawei/hinic networking/i40e networking/device_drivers/ethernet/intel/i40e networking/iavf networking/device_drivers/ethernet/intel/iavf networking/ice networking/device_drivers/ethernet/intel/ice networking/igb networking/device_drivers/ethernet/intel/igb networking/igbvf networking/device_drivers/ethernet/intel/igbvf -networking/iphase networking/device_drivers/atm/iphase networking/ixgbe networking/device_drivers/ethernet/intel/ixgbe networking/ixgbevf networking/device_drivers/ethernet/intel/ixgbevf networking/netdev-FAQ process/maintainer-netdev diff --git a/Documentation/networking/device_drivers/atm/fore200e.rst b/Documentation/networking/device_drivers/atm/fore200e.rst deleted file mode 100644 index 55df9ec09ac8..000000000000 --- a/Documentation/networking/device_drivers/atm/fore200e.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -============================================= -FORE Systems PCA-200E/SBA-200E ATM NIC driver -============================================= - -This driver adds support for the FORE Systems 200E-series ATM adapters -to the Linux operating system. It is based on the earlier PCA-200E driver -written by Uwe Dannowski. - -The driver simultaneously supports PCA-200E and SBA-200E adapters on -i386, alpha (untested), powerpc, sparc and sparc64 archs. - -The intent is to enable the use of different models of FORE adapters at the -same time, by hosts that have several bus interfaces (such as PCI+SBUS, -or PCI+EISA). - -Only PCI and SBUS devices are currently supported by the driver, but support -for other bus interfaces such as EISA should not be too hard to add. - - -Firmware Copyright Notice -------------------------- - -Please read the fore200e_firmware_copyright file present -in the linux/drivers/atm directory for details and restrictions. - - -Firmware Updates ----------------- - -The FORE Systems 200E-series driver is shipped with firmware data being -uploaded to the ATM adapters at system boot time or at module loading time. -The supplied firmware images should work with all adapters. - -However, if you encounter problems (the firmware doesn't start or the driver -is unable to read the PROM data), you may consider trying another firmware -version. Alternative binary firmware images can be found somewhere on the -ForeThought CD-ROM supplied with your adapter by FORE Systems. - -You can also get the latest firmware images from FORE Systems at -https://en.wikipedia.org/wiki/FORE_Systems. Register TACTics Online and go to -the 'software updates' pages. The firmware binaries are part of -the various ForeThought software distributions. - -Notice that different versions of the PCA-200E firmware exist, depending -on the endianness of the host architecture. The driver is shipped with -both little and big endian PCA firmware images. - -Name and location of the new firmware images can be set at kernel -configuration time: - -1. Copy the new firmware binary files (with .bin, .bin1 or .bin2 suffix) - to some directory, such as linux/drivers/atm. - -2. Reconfigure your kernel to set the new firmware name and location. - Expected pathnames are absolute or relative to the drivers/atm directory. - -3. Rebuild and re-install your kernel or your module. - - -Feedback --------- - -Feedback is welcome. Please send success stories/bug reports/ -patches/improvement/comments/flames to . diff --git a/Documentation/networking/device_drivers/atm/index.rst b/Documentation/networking/device_drivers/atm/index.rst index 724552ca0be4..9392c86f48bc 100644 --- a/Documentation/networking/device_drivers/atm/index.rst +++ b/Documentation/networking/device_drivers/atm/index.rst @@ -9,5 +9,3 @@ Asynchronous Transfer Mode (ATM) Device Drivers :maxdepth: 2 cxacru - fore200e - iphase diff --git a/Documentation/networking/device_drivers/atm/iphase.rst b/Documentation/networking/device_drivers/atm/iphase.rst deleted file mode 100644 index 388c7101e2cb..000000000000 --- a/Documentation/networking/device_drivers/atm/iphase.rst +++ /dev/null @@ -1,193 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -================================== -ATM (i)Chip IA Linux Driver Source -================================== - - READ ME FIRST - --------------------------------------------------------------------------------- - - Read This Before You Begin! - --------------------------------------------------------------------------------- - -Description -=========== - -This is the README file for the Interphase PCI ATM (i)Chip IA Linux driver -source release. - -The features and limitations of this driver are as follows: - - - A single VPI (VPI value of 0) is supported. - - Supports 4K VCs for the server board (with 512K control memory) and 1K - VCs for the client board (with 128K control memory). - - UBR, ABR and CBR service categories are supported. - - Only AAL5 is supported. - - Supports setting of PCR on the VCs. - - Multiple adapters in a system are supported. - - All variants of Interphase ATM PCI (i)Chip adapter cards are supported, - including x575 (OC3, control memory 128K , 512K and packet memory 128K, - 512K and 1M), x525 (UTP25) and x531 (DS3 and E3). See - http://www.iphase.com/ - for details. - - Only x86 platforms are supported. - - SMP is supported. - - -Before You Start -================ - - -Installation ------------- - -1. Installing the adapters in the system - - To install the ATM adapters in the system, follow the steps below. - - a. Login as root. - b. Shut down the system and power off the system. - c. Install one or more ATM adapters in the system. - d. Connect each adapter to a port on an ATM switch. The green 'Link' - LED on the front panel of the adapter will be on if the adapter is - connected to the switch properly when the system is powered up. - e. Power on and boot the system. - -2. [ Removed ] - -3. Rebuild kernel with ABR support - - [ a. and b. removed ] - - c. Reconfigure the kernel, choose the Interphase ia driver through "make - menuconfig" or "make xconfig". - d. Rebuild the kernel, loadable modules and the atm tools. - e. Install the new built kernel and modules and reboot. - -4. Load the adapter hardware driver (ia driver) if it is built as a module - - a. Login as root. - b. Change directory to /lib/modules//atm. - c. Run "insmod suni.o;insmod iphase.o" - The yellow 'status' LED on the front panel of the adapter will blink - while the driver is loaded in the system. - d. To verify that the 'ia' driver is loaded successfully, run the - following command:: - - cat /proc/atm/devices - - If the driver is loaded successfully, the output of the command will - be similar to the following lines:: - - Itf Type ESI/"MAC"addr AAL(TX,err,RX,err,drop) ... - 0 ia xxxxxxxxx 0 ( 0 0 0 0 0 ) 5 ( 0 0 0 0 0 ) - - You can also check the system log file /var/log/messages for messages - related to the ATM driver. - -5. Ia Driver Configuration - -5.1 Configuration of adapter buffers - The (i)Chip boards have 3 different packet RAM size variants: 128K, 512K and - 1M. The RAM size decides the number of buffers and buffer size. The default - size and number of buffers are set as following: - - ========= ======= ====== ====== ====== ====== ====== - Total Rx RAM Tx RAM Rx Buf Tx Buf Rx buf Tx buf - RAM size size size size size cnt cnt - ========= ======= ====== ====== ====== ====== ====== - 128K 64K 64K 10K 10K 6 6 - 512K 256K 256K 10K 10K 25 25 - 1M 512K 512K 10K 10K 51 51 - ========= ======= ====== ====== ====== ====== ====== - - These setting should work well in most environments, but can be - changed by typing the following command:: - - insmod /ia.o IA_RX_BUF= IA_RX_BUF_SZ= \ - IA_TX_BUF= IA_TX_BUF_SZ= - - Where: - - - RX_CNT = number of receive buffers in the range (1-128) - - RX_SIZE = size of receive buffers in the range (48-64K) - - TX_CNT = number of transmit buffers in the range (1-128) - - TX_SIZE = size of transmit buffers in the range (48-64K) - - 1. Transmit and receive buffer size must be a multiple of 4. - 2. Care should be taken so that the memory required for the - transmit and receive buffers is less than or equal to the - total adapter packet memory. - -5.2 Turn on ia debug trace - - When the ia driver is built with the CONFIG_ATM_IA_DEBUG flag, the driver - can provide more debug trace if needed. There is a bit mask variable, - IADebugFlag, which controls the output of the traces. You can find the bit - map of the IADebugFlag in iphase.h. - The debug trace can be turn on through the insmod command line option, for - example, "insmod iphase.o IADebugFlag=0xffffffff" can turn on all the debug - traces together with loading the driver. - -6. Ia Driver Test Using ttcp_atm and PVC - - For the PVC setup, the test machines can either be connected back-to-back or - through a switch. If connected through the switch, the switch must be - configured for the PVC(s). - - a. For UBR test: - - At the test machine intended to receive data, type:: - - ttcp_atm -r -a -s 0.100 - - At the other test machine, type:: - - ttcp_atm -t -a -s 0.100 -n 10000 - - Run "ttcp_atm -h" to display more options of the ttcp_atm tool. - b. For ABR test: - - It is the same as the UBR testing, but with an extra command option:: - - -Pabr:max_pcr= - - where: - - xxx = the maximum peak cell rate, from 170 - 353207. - - This option must be set on both the machines. - - c. For CBR test: - - It is the same as the UBR testing, but with an extra command option:: - - -Pcbr:max_pcr= - - where: - - xxx = the maximum peak cell rate, from 170 - 353207. - - This option may only be set on the transmit machine. - - -Outstanding Issues -================== - - - -Contact Information -------------------- - -:: - - Customer Support: - United States: Telephone: (214) 654-5555 - Fax: (214) 654-5500 - E-Mail: intouch@iphase.com - Europe: Telephone: 33 (0)1 41 15 44 00 - Fax: 33 (0)1 41 15 12 13 - World Wide Web: http://www.iphase.com - Anonymous FTP: ftp.iphase.com diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig deleted file mode 100644 index 63cdb46a3439..000000000000 --- a/drivers/atm/Kconfig +++ /dev/null @@ -1,325 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# ATM device configuration -# - -menuconfig ATM_DRIVERS - bool "ATM drivers" - depends on NETDEVICES && ATM - default y - help - Say Y here to get to see options for Asynchronous Transfer Mode - device drivers. This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if ATM_DRIVERS && NETDEVICES && ATM - -config ATM_DUMMY - tristate "Dummy ATM driver" - help - Dummy ATM driver. Useful for proxy signalling, testing, - and development. If unsure, say N. - -config ATM_TCP - tristate "ATM over TCP" - depends on INET - help - ATM over TCP driver. Useful mainly for development and for - experiments. If unsure, say N. - -config ATM_LANAI - tristate "Efficient Networks Speedstream 3010" - depends on PCI && ATM - help - Supports ATM cards based on the Efficient Networks "Lanai" - chipset such as the Speedstream 3010 and the ENI-25p. The - Speedstream 3060 is currently not supported since we don't - have the code to drive the on-board Alcatel DSL chipset (yet). - -config ATM_ENI - tristate "Efficient Networks ENI155P" - depends on PCI - help - Driver for the Efficient Networks ENI155p series and SMC ATM - Power155 155 Mbps ATM adapters. Both, the versions with 512KB and - 2MB on-board RAM (Efficient calls them "C" and "S", respectively), - and the FPGA and the ASIC Tonga versions of the board are supported. - The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) - adapters. - - To compile this driver as a module, choose M here: the module will - be called eni. - -config ATM_ENI_DEBUG - bool "Enable extended debugging" - depends on ATM_ENI - help - Extended debugging records various events and displays that list - when an inconsistency is detected. This mechanism is faster than - generally using printks, but still has some impact on performance. - Note that extended debugging may create certain race conditions - itself. Enable this ONLY if you suspect problems with the driver. - -config ATM_ENI_TUNE_BURST - bool "Fine-tune burst settings" - depends on ATM_ENI - help - In order to obtain good throughput, the ENI NIC can transfer - multiple words of data per PCI bus access cycle. Such a multi-word - transfer is called a burst. - - The default settings for the burst sizes are suitable for most PCI - chipsets. However, in some cases, large bursts may overrun buffers - in the PCI chipset and cause data corruption. In such cases, large - bursts must be disabled and only (slower) small bursts can be used. - The burst sizes can be set independently in the send (TX) and - receive (RX) direction. - - Note that enabling many different burst sizes in the same direction - may increase the cost of setting up a transfer such that the - resulting throughput is lower than when using only the largest - available burst size. - - Also, sometimes larger bursts lead to lower throughput, e.g. on an - Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed - when going from 8W to 16W bursts. - -config ATM_ENI_BURST_TX_16W - bool "Enable 16W TX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst sixteen words at once in the send direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets. - -config ATM_ENI_BURST_TX_8W - bool "Enable 8W TX bursts (recommended)" - depends on ATM_ENI_TUNE_BURST - help - Burst eight words at once in the send direction. This is the default - setting. - -config ATM_ENI_BURST_TX_4W - bool "Enable 4W TX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst four words at once in the send direction. You may want to try - this if you have disabled 8W bursts. Enabling 4W if 8W is also set - may or may not improve throughput. - -config ATM_ENI_BURST_TX_2W - bool "Enable 2W TX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst two words at once in the send direction. You may want to try - this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W - are also set may or may not improve throughput. - -config ATM_ENI_BURST_RX_16W - bool "Enable 16W RX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst sixteen words at once in the receive direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets. - -config ATM_ENI_BURST_RX_8W - bool "Enable 8W RX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst eight words at once in the receive direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets, - such as the Intel Neptune series. - -config ATM_ENI_BURST_RX_4W - bool "Enable 4W RX bursts (recommended)" - depends on ATM_ENI_TUNE_BURST - help - Burst four words at once in the receive direction. This is the - default setting. Enabling 4W if 8W is also set may or may not - improve throughput. - -config ATM_ENI_BURST_RX_2W - bool "Enable 2W RX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst two words at once in the receive direction. You may want to - try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or - 8W are also set may or may not improve throughput. - -config ATM_NICSTAR - tristate "IDT 77201 (NICStAR) (ForeRunnerLE)" - depends on PCI - help - The NICStAR chipset family is used in a large number of ATM NICs for - 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE - series. Say Y if you have one of those. - - To compile this driver as a module, choose M here: the module will - be called nicstar. - -config ATM_NICSTAR_USE_SUNI - bool "Use suni PHY driver (155Mbps)" - depends on ATM_NICSTAR - help - Support for the S-UNI and compatible PHYsical layer chips. These are - found in most 155Mbps NICStAR based ATM cards, namely in the - ForeRunner LE155 cards. This driver provides detection of cable~ - removal and reinsertion and provides some statistics. This driver - doesn't have removal capability when compiled as a module, so if you - need that capability don't include S-UNI support (it's not needed to - make the card work). - -config ATM_NICSTAR_USE_IDT77105 - bool "Use IDT77105 PHY driver (25Mbps)" - depends on ATM_NICSTAR - help - Support for the PHYsical layer chip in ForeRunner LE25 cards. In - addition to cable removal/reinsertion detection, this driver allows - you to control the loopback mode of the chip via a dedicated IOCTL. - This driver is required for proper handling of temporary carrier - loss, so if you have a 25Mbps NICStAR based ATM card you must say Y. - -config ATM_IDT77252 - tristate "IDT 77252 (NICStAR II)" - depends on PCI - help - Driver for the IDT 77252 ATM PCI chips. - - To compile this driver as a module, choose M here: the module will - be called idt77252. - -config ATM_IDT77252_DEBUG - bool "Enable debugging messages" - depends on ATM_IDT77252 - help - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument. See the file for - the meanings of the bits in the mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_IDT77252_RCV_ALL - bool "Receive ALL cells in raw queue" - depends on ATM_IDT77252 - help - Enable receiving of all cells on the ATM link, that do not match - an open connection in the raw cell queue of the driver. Useful - for debugging or special applications only, so the safe answer is N. - -config ATM_IDT77252_USE_SUNI - bool - depends on ATM_IDT77252 - default y - -config ATM_IA - tristate "Interphase ATM PCI x575/x525/x531" - depends on PCI - help - This is a driver for the Interphase (i)ChipSAR adapter cards - which include a variety of variants in term of the size of the - control memory (128K-1KVC, 512K-4KVC), the size of the packet - memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, - UTP155, UTP25, DS3 and E3). Go to: - - for more info about the cards. Say Y (or M to compile as a module - named iphase) here if you have one of these cards. - - See the file - - for further details. - -config ATM_IA_DEBUG - bool "Enable debugging messages" - depends on ATM_IA - help - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument (kernel command line argument as well?), changed - dynamically using an ioctl (Get the debug utility, iadbg, from - ). - - See the file for the meanings of the - bits in the mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_FORE200E - tristate "FORE Systems 200E-series" - depends on (PCI || SBUS) - select FW_LOADER - help - This is a driver for the FORE Systems 200E-series ATM adapter - cards. It simultaneously supports PCA-200E and SBA-200E models - on PCI and SBUS hosts. Say Y (or M to compile as a module - named fore_200e) here if you have one of these ATM adapters. - - See the file - for - further details. - -config ATM_FORE200E_USE_TASKLET - bool "Defer interrupt work to a tasklet" - depends on ATM_FORE200E - default n - help - This defers work to be done by the interrupt handler to a - tasklet instead of handling everything at interrupt time. This - may improve the responsive of the host. - -config ATM_FORE200E_TX_RETRY - int "Maximum number of tx retries" - depends on ATM_FORE200E - default "16" - help - Specifies the number of times the driver attempts to transmit - a message before giving up, if the transmit queue of the ATM card - is transiently saturated. - - Saturation of the transmit queue may occur only under extreme - conditions, e.g. when a fast host continuously submits very small - frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. - - Note that under common conditions, it is unlikely that you encounter - a saturation of the transmit queue, so the retry mechanism never - comes into play. - -config ATM_FORE200E_DEBUG - int "Debugging level (0-3)" - depends on ATM_FORE200E - default "0" - help - Specifies the level of debugging messages issued by the driver. - The verbosity of the driver increases with the value of this - parameter. - - When active, these messages can have a significant impact on - the performances of the driver, and the size of your syslog files! - Keep the debugging level to 0 during normal operations. - -config ATM_HE - tristate "ForeRunner HE Series" - depends on PCI - help - This is a driver for the Marconi ForeRunner HE-series ATM adapter - cards. It simultaneously supports the 155 and 622 versions. - -config ATM_HE_USE_SUNI - bool "Use S/UNI PHY driver" - depends on ATM_HE - help - Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner - HE cards. This driver provides carrier detection some statistics. - -config ATM_SOLOS - tristate "Solos ADSL2+ PCI Multiport card driver" - depends on PCI - select FW_LOADER - help - Support for the Solos multiport ADSL2+ card. - -endif # ATM diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8ec98f6dfef9..19cc389028ba 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -501,8 +501,6 @@ config SUNGEM_PHY source "drivers/net/arcnet/Kconfig" -source "drivers/atm/Kconfig" - source "drivers/net/dsa/Kconfig" source "drivers/net/ethernet/Kconfig" diff --git a/net/atm/Kconfig b/net/atm/Kconfig index 77343d57ff2a..9a2f376d3d2b 100644 --- a/net/atm/Kconfig +++ b/net/atm/Kconfig @@ -14,61 +14,3 @@ config ATM In order to participate in an ATM network, your Linux box needs an ATM networking card. If you have that, say Y here and to the driver of your ATM card below. - - Note that you need a set of user-space programs to actually make use - of ATM. See the file for - further details. - -config ATM_CLIP - tristate "Classical IP over ATM" - depends on ATM && INET - help - Classical IP over ATM for PVCs and SVCs, supporting InARP and - ATMARP. If you want to communication with other IP hosts on your ATM - network, you will typically either say Y here or to "LAN Emulation - (LANE)" below. - -config ATM_CLIP_NO_ICMP - bool "Do NOT send ICMP if no neighbour" - depends on ATM_CLIP - help - Normally, an "ICMP host unreachable" message is sent if a neighbour - cannot be reached because there is no VC to it in the kernel's - ATMARP table. This may cause problems when ATMARP table entries are - briefly removed during revalidation. If you say Y here, packets to - such neighbours are silently discarded instead. - -config ATM_LANE - tristate "LAN Emulation (LANE) support" - depends on ATM - help - LAN Emulation emulates services of existing LANs across an ATM - network. Besides operating as a normal ATM end station client, Linux - LANE client can also act as an proxy client bridging packets between - ELAN and Ethernet segments. You need LANE if you want to try MPOA. - -config ATM_MPOA - tristate "Multi-Protocol Over ATM (MPOA) support" - depends on ATM && INET && ATM_LANE!=n - help - Multi-Protocol Over ATM allows ATM edge devices such as routers, - bridges and ATM attached hosts establish direct ATM VCs across - subnetwork boundaries. These shortcut connections bypass routers - enhancing overall network performance. - -config ATM_BR2684 - tristate "RFC1483/2684 Bridged protocols" - depends on ATM && INET - help - ATM PVCs can carry ethernet PDUs according to RFC2684 (formerly 1483) - This device will act like an ethernet from the kernels point of view, - with the traffic being carried by ATM PVCs (currently 1 PVC/device). - This is sometimes used over DSL lines. If in doubt, say N. - -config ATM_BR2684_IPFILTER - bool "Per-VC IP filter kludge" - depends on ATM_BR2684 - help - This is an experimental mechanism for users who need to terminate a - large number of IP-only vcc's. Do not enable this unless you are sure - you know what you are doing. diff --git a/drivers/Makefile b/drivers/Makefile index 0841ea851847..cc5fdb1ef79f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -90,7 +90,6 @@ obj-$(CONFIG_SPMI) += spmi/ obj-$(CONFIG_HSI) += hsi/ obj-$(CONFIG_SLIMBUS) += slimbus/ obj-y += net/ -obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_FUSION) += message/ obj-y += firewire/ obj-$(CONFIG_UIO) += uio/ diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile deleted file mode 100644 index c9eade92019b..000000000000 --- a/drivers/atm/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Linux network (ATM) device drivers. -# - -fore_200e-y := fore200e.o - -obj-$(CONFIG_ATM_NICSTAR) += nicstar.o -obj-$(CONFIG_ATM_IA) += iphase.o suni.o -obj-$(CONFIG_ATM_FORE200E) += fore_200e.o -obj-$(CONFIG_ATM_ENI) += eni.o suni.o -obj-$(CONFIG_ATM_IDT77252) += idt77252.o -obj-$(CONFIG_ATM_SOLOS) += solos-pci.o - -ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) - obj-$(CONFIG_ATM_NICSTAR) += suni.o -endif -ifeq ($(CONFIG_ATM_NICSTAR_USE_IDT77105),y) - obj-$(CONFIG_ATM_NICSTAR) += idt77105.o -endif -ifeq ($(CONFIG_ATM_IDT77252_USE_SUNI),y) - obj-$(CONFIG_ATM_IDT77252) += suni.o -endif - -obj-$(CONFIG_ATM_DUMMY) += adummy.o -obj-$(CONFIG_ATM_TCP) += atmtcp.o -obj-$(CONFIG_ATM_LANAI) += lanai.o - -obj-$(CONFIG_ATM_HE) += he.o -ifeq ($(CONFIG_ATM_HE_USE_SUNI),y) - obj-$(CONFIG_ATM_HE) += suni.o -endif diff --git a/net/atm/Makefile b/net/atm/Makefile index bfec0f2d83b5..226eecbe3825 100644 --- a/net/atm/Makefile +++ b/net/atm/Makefile @@ -4,13 +4,7 @@ # atm-y := addr.o pvc.o signaling.o svc.o ioctl.o common.o atm_misc.o raw.o resources.o atm_sysfs.o -mpoa-objs := mpc.o mpoa_caches.o mpoa_proc.o - -obj-$(CONFIG_ATM) += atm.o -obj-$(CONFIG_ATM_CLIP) += clip.o -obj-$(CONFIG_ATM_BR2684) += br2684.o atm-$(CONFIG_PROC_FS) += proc.o -obj-$(CONFIG_ATM_LANE) += lec.o -obj-$(CONFIG_ATM_MPOA) += mpoa.o +obj-$(CONFIG_ATM) += atm.o obj-$(CONFIG_PPPOATM) += pppoatm.o diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h deleted file mode 100644 index de1ed802cbf8..000000000000 --- a/drivers/atm/eni.h +++ /dev/null @@ -1,136 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - - -#ifndef DRIVER_ATM_ENI_H -#define DRIVER_ATM_ENI_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "midway.h" - - -#define DEV_LABEL "eni" - -#define UBR_BUFFER (128*1024) /* UBR buffer size */ - -#define RX_DMA_BUF 8 /* burst and skip a few things */ -#define TX_DMA_BUF 100 /* should be enough for 64 kB */ - -#define DEFAULT_RX_MULT 300 /* max_sdu*3 */ -#define DEFAULT_TX_MULT 300 /* max_sdu*3 */ - -#define ENI_ZEROES_SIZE 4 /* need that many DMA-able zero bytes */ - - -struct eni_free { - void __iomem *start; /* counting in bytes */ - int order; -}; - -struct eni_tx { - void __iomem *send; /* base, 0 if unused */ - int prescaler; /* shaping prescaler */ - int resolution; /* shaping divider */ - unsigned long tx_pos; /* current TX write position */ - unsigned long words; /* size of TX queue */ - int index; /* TX channel number */ - int reserved; /* reserved peak cell rate */ - int shaping; /* shaped peak cell rate */ - struct sk_buff_head backlog; /* queue of waiting TX buffers */ -}; - -struct eni_vcc { - int (*rx)(struct atm_vcc *vcc); /* RX function, NULL if none */ - void __iomem *recv; /* receive buffer */ - unsigned long words; /* its size in words */ - unsigned long descr; /* next descriptor (RX) */ - unsigned long rx_pos; /* current RX descriptor pos */ - struct eni_tx *tx; /* TXer, NULL if none */ - int rxing; /* number of pending PDUs */ - int servicing; /* number of waiting VCs (0 or 1) */ - int txing; /* number of pending TX bytes */ - ktime_t timestamp; /* for RX timing */ - struct atm_vcc *next; /* next pending RX */ - struct sk_buff *last; /* last PDU being DMAed (used to carry - discard information) */ -}; - -struct eni_dev { - /*-------------------------------- spinlock */ - spinlock_t lock; /* sync with interrupt */ - struct tasklet_struct task; /* tasklet for interrupt work */ - u32 events; /* pending events */ - /*-------------------------------- base pointers into Midway address - space */ - void __iomem *ioaddr; - void __iomem *phy; /* PHY interface chip registers */ - void __iomem *reg; /* register base */ - void __iomem *ram; /* RAM base */ - void __iomem *vci; /* VCI table */ - void __iomem *rx_dma; /* RX DMA queue */ - void __iomem *tx_dma; /* TX DMA queue */ - void __iomem *service; /* service list */ - /*-------------------------------- TX part */ - struct eni_tx tx[NR_CHAN]; /* TX channels */ - struct eni_tx *ubr; /* UBR channel */ - struct sk_buff_head tx_queue; /* PDUs currently being TX DMAed*/ - wait_queue_head_t tx_wait; /* for close */ - int tx_bw; /* remaining bandwidth */ - u32 dma[TX_DMA_BUF*2]; /* DMA request scratch area */ - struct eni_zero { /* aligned "magic" zeroes */ - u32 *addr; - dma_addr_t dma; - } zero; - int tx_mult; /* buffer size multiplier (percent) */ - /*-------------------------------- RX part */ - u32 serv_read; /* host service read index */ - struct atm_vcc *fast,*last_fast;/* queues of VCCs with pending PDUs */ - struct atm_vcc *slow,*last_slow; - struct atm_vcc **rx_map; /* for fast lookups */ - struct sk_buff_head rx_queue; /* PDUs currently being RX-DMAed */ - wait_queue_head_t rx_wait; /* for close */ - int rx_mult; /* buffer size multiplier (percent) */ - /*-------------------------------- statistics */ - unsigned long lost; /* number of lost cells (RX) */ - /*-------------------------------- memory management */ - unsigned long base_diff; /* virtual-real base address */ - int free_len; /* free list length */ - struct eni_free *free_list; /* free list */ - int free_list_size; /* maximum size of free list */ - /*-------------------------------- ENI links */ - struct atm_dev *more; /* other ENI devices */ - /*-------------------------------- general information */ - int mem; /* RAM on board (in bytes) */ - int asic; /* PCI interface type, 0 for FPGA */ - unsigned int irq; /* IRQ */ - struct pci_dev *pci_dev; /* PCI stuff */ -}; - - -#define ENI_DEV(d) ((struct eni_dev *) (d)->dev_data) -#define ENI_VCC(d) ((struct eni_vcc *) (d)->dev_data) - - -struct eni_skb_prv { - struct atm_skb_data _; /* reserved */ - unsigned long pos; /* position of next descriptor */ - int size; /* PDU size in reassembly buffer */ - dma_addr_t paddr; /* DMA handle */ -}; - -#define ENI_PRV_SIZE(skb) (((struct eni_skb_prv *) (skb)->cb)->size) -#define ENI_PRV_POS(skb) (((struct eni_skb_prv *) (skb)->cb)->pos) -#define ENI_PRV_PADDR(skb) (((struct eni_skb_prv *) (skb)->cb)->paddr) - -#endif diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h deleted file mode 100644 index 5d95fe9fd836..000000000000 --- a/drivers/atm/fore200e.h +++ /dev/null @@ -1,973 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _FORE200E_H -#define _FORE200E_H - -#ifdef __KERNEL__ - -/* rx buffer sizes */ - -#define SMALL_BUFFER_SIZE 384 /* size of small buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ -#define LARGE_BUFFER_SIZE 4032 /* size of large buffers (multiple of 48 (PCA) and 64 (SBA) bytes) */ - - -#define RBD_BLK_SIZE 32 /* nbr of supplied rx buffers per rbd */ - - -#define MAX_PDU_SIZE 65535 /* maximum PDU size supported by AALs */ - - -#define BUFFER_S1_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 1 */ -#define BUFFER_L1_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 1 */ - -#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ -#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ - -#define BUFFER_S1_NBR (RBD_BLK_SIZE * 6) -#define BUFFER_L1_NBR (RBD_BLK_SIZE * 4) - -#define BUFFER_S2_NBR (RBD_BLK_SIZE * 6) -#define BUFFER_L2_NBR (RBD_BLK_SIZE * 4) - - -#define QUEUE_SIZE_CMD 16 /* command queue capacity */ -#define QUEUE_SIZE_RX 64 /* receive queue capacity */ -#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ -#define QUEUE_SIZE_BS 32 /* buffer supply queue capacity */ - -#define FORE200E_VPI_BITS 0 -#define FORE200E_VCI_BITS 10 -#define NBR_CONNECT (1 << (FORE200E_VPI_BITS + FORE200E_VCI_BITS)) /* number of connections */ - - -#define TSD_FIXED 2 -#define TSD_EXTENSION 0 -#define TSD_NBR (TSD_FIXED + TSD_EXTENSION) - - -/* the cp starts putting a received PDU into one *small* buffer, - then it uses a number of *large* buffers for the trailing data. - we compute here the total number of receive segment descriptors - required to hold the largest possible PDU */ - -#define RSD_REQUIRED (((MAX_PDU_SIZE - SMALL_BUFFER_SIZE + LARGE_BUFFER_SIZE) / LARGE_BUFFER_SIZE) + 1) - -#define RSD_FIXED 3 - -/* RSD_REQUIRED receive segment descriptors are enough to describe a max-sized PDU, - but we have to keep the size of the receive PDU descriptor multiple of 32 bytes, - so we add one extra RSD to RSD_EXTENSION - (WARNING: THIS MAY CHANGE IF BUFFER SIZES ARE MODIFIED) */ - -#define RSD_EXTENSION ((RSD_REQUIRED - RSD_FIXED) + 1) -#define RSD_NBR (RSD_FIXED + RSD_EXTENSION) - - -#define FORE200E_DEV(d) ((struct fore200e*)((d)->dev_data)) -#define FORE200E_VCC(d) ((struct fore200e_vcc*)((d)->dev_data)) - -/* bitfields endian games */ - -#if defined(__LITTLE_ENDIAN_BITFIELD) -#define BITFIELD2(b1, b2) b1; b2; -#define BITFIELD3(b1, b2, b3) b1; b2; b3; -#define BITFIELD4(b1, b2, b3, b4) b1; b2; b3; b4; -#define BITFIELD5(b1, b2, b3, b4, b5) b1; b2; b3; b4; b5; -#define BITFIELD6(b1, b2, b3, b4, b5, b6) b1; b2; b3; b4; b5; b6; -#elif defined(__BIG_ENDIAN_BITFIELD) -#define BITFIELD2(b1, b2) b2; b1; -#define BITFIELD3(b1, b2, b3) b3; b2; b1; -#define BITFIELD4(b1, b2, b3, b4) b4; b3; b2; b1; -#define BITFIELD5(b1, b2, b3, b4, b5) b5; b4; b3; b2; b1; -#define BITFIELD6(b1, b2, b3, b4, b5, b6) b6; b5; b4; b3; b2; b1; -#else -#error unknown bitfield endianess -#endif - - -/* ATM cell header (minus HEC byte) */ - -typedef struct atm_header { - BITFIELD5( - u32 clp : 1, /* cell loss priority */ - u32 plt : 3, /* payload type */ - u32 vci : 16, /* virtual channel identifier */ - u32 vpi : 8, /* virtual path identifier */ - u32 gfc : 4 /* generic flow control */ - ) -} atm_header_t; - - -/* ATM adaptation layer id */ - -typedef enum fore200e_aal { - FORE200E_AAL0 = 0, - FORE200E_AAL34 = 4, - FORE200E_AAL5 = 5, -} fore200e_aal_t; - - -/* transmit PDU descriptor specification */ - -typedef struct tpd_spec { - BITFIELD4( - u32 length : 16, /* total PDU length */ - u32 nseg : 8, /* number of transmit segments */ - enum fore200e_aal aal : 4, /* adaptation layer */ - u32 intr : 4 /* interrupt requested */ - ) -} tpd_spec_t; - - -/* transmit PDU rate control */ - -typedef struct tpd_rate -{ - BITFIELD2( - u32 idle_cells : 16, /* number of idle cells to insert */ - u32 data_cells : 16 /* number of data cells to transmit */ - ) -} tpd_rate_t; - - -/* transmit segment descriptor */ - -typedef struct tsd { - u32 buffer; /* transmit buffer DMA address */ - u32 length; /* number of bytes in buffer */ -} tsd_t; - - -/* transmit PDU descriptor */ - -typedef struct tpd { - struct atm_header atm_header; /* ATM header minus HEC byte */ - struct tpd_spec spec; /* tpd specification */ - struct tpd_rate rate; /* tpd rate control */ - u32 pad; /* reserved */ - struct tsd tsd[ TSD_NBR ]; /* transmit segment descriptors */ -} tpd_t; - - -/* receive segment descriptor */ - -typedef struct rsd { - u32 handle; /* host supplied receive buffer handle */ - u32 length; /* number of bytes in buffer */ -} rsd_t; - - -/* receive PDU descriptor */ - -typedef struct rpd { - struct atm_header atm_header; /* ATM header minus HEC byte */ - u32 nseg; /* number of receive segments */ - struct rsd rsd[ RSD_NBR ]; /* receive segment descriptors */ -} rpd_t; - - -/* buffer scheme */ - -typedef enum buffer_scheme { - BUFFER_SCHEME_ONE, - BUFFER_SCHEME_TWO, - BUFFER_SCHEME_NBR /* always last */ -} buffer_scheme_t; - - -/* buffer magnitude */ - -typedef enum buffer_magn { - BUFFER_MAGN_SMALL, - BUFFER_MAGN_LARGE, - BUFFER_MAGN_NBR /* always last */ -} buffer_magn_t; - - -/* receive buffer descriptor */ - -typedef struct rbd { - u32 handle; /* host supplied handle */ - u32 buffer_haddr; /* host DMA address of host buffer */ -} rbd_t; - - -/* receive buffer descriptor block */ - -typedef struct rbd_block { - struct rbd rbd[ RBD_BLK_SIZE ]; /* receive buffer descriptor */ -} rbd_block_t; - - -/* tpd DMA address */ - -typedef struct tpd_haddr { - BITFIELD3( - u32 size : 4, /* tpd size expressed in 32 byte blocks */ - u32 pad : 1, /* reserved */ - u32 haddr : 27 /* tpd DMA addr aligned on 32 byte boundary */ - ) -} tpd_haddr_t; - -#define TPD_HADDR_SHIFT 5 /* addr aligned on 32 byte boundary */ - -/* cp resident transmit queue entry */ - -typedef struct cp_txq_entry { - struct tpd_haddr tpd_haddr; /* host DMA address of tpd */ - u32 status_haddr; /* host DMA address of completion status */ -} cp_txq_entry_t; - - -/* cp resident receive queue entry */ - -typedef struct cp_rxq_entry { - u32 rpd_haddr; /* host DMA address of rpd */ - u32 status_haddr; /* host DMA address of completion status */ -} cp_rxq_entry_t; - - -/* cp resident buffer supply queue entry */ - -typedef struct cp_bsq_entry { - u32 rbd_block_haddr; /* host DMA address of rbd block */ - u32 status_haddr; /* host DMA address of completion status */ -} cp_bsq_entry_t; - - -/* completion status */ - -typedef volatile enum status { - STATUS_PENDING = (1<<0), /* initial status (written by host) */ - STATUS_COMPLETE = (1<<1), /* completion status (written by cp) */ - STATUS_FREE = (1<<2), /* initial status (written by host) */ - STATUS_ERROR = (1<<3) /* completion status (written by cp) */ -} status_t; - - -/* cp operation code */ - -typedef enum opcode { - OPCODE_INITIALIZE = 1, /* initialize board */ - OPCODE_ACTIVATE_VCIN, /* activate incoming VCI */ - OPCODE_ACTIVATE_VCOUT, /* activate outgoing VCI */ - OPCODE_DEACTIVATE_VCIN, /* deactivate incoming VCI */ - OPCODE_DEACTIVATE_VCOUT, /* deactivate incoing VCI */ - OPCODE_GET_STATS, /* get board statistics */ - OPCODE_SET_OC3, /* set OC-3 registers */ - OPCODE_GET_OC3, /* get OC-3 registers */ - OPCODE_RESET_STATS, /* reset board statistics */ - OPCODE_GET_PROM, /* get expansion PROM data (PCI specific) */ - OPCODE_SET_VPI_BITS, /* set x bits of those decoded by the - firmware to be low order bits from - the VPI field of the ATM cell header */ - OPCODE_REQUEST_INTR = (1<<7) /* request interrupt */ -} opcode_t; - - -/* virtual path / virtual channel identifiers */ - -typedef struct vpvc { - BITFIELD3( - u32 vci : 16, /* virtual channel identifier */ - u32 vpi : 8, /* virtual path identifier */ - u32 pad : 8 /* reserved */ - ) -} vpvc_t; - - -/* activate VC command opcode */ - -typedef struct activate_opcode { - BITFIELD4( - enum opcode opcode : 8, /* cp opcode */ - enum fore200e_aal aal : 8, /* adaptation layer */ - enum buffer_scheme scheme : 8, /* buffer scheme */ - u32 pad : 8 /* reserved */ - ) -} activate_opcode_t; - - -/* activate VC command block */ - -typedef struct activate_block { - struct activate_opcode opcode; /* activate VC command opcode */ - struct vpvc vpvc; /* VPI/VCI */ - u32 mtu; /* for AAL0 only */ - -} activate_block_t; - - -/* deactivate VC command opcode */ - -typedef struct deactivate_opcode { - BITFIELD2( - enum opcode opcode : 8, /* cp opcode */ - u32 pad : 24 /* reserved */ - ) -} deactivate_opcode_t; - - -/* deactivate VC command block */ - -typedef struct deactivate_block { - struct deactivate_opcode opcode; /* deactivate VC command opcode */ - struct vpvc vpvc; /* VPI/VCI */ -} deactivate_block_t; - - -/* OC-3 registers */ - -typedef struct oc3_regs { - u32 reg[ 128 ]; /* see the PMC Sierra PC5346 S/UNI-155-Lite - Saturn User Network Interface documentation - for a description of the OC-3 chip registers */ -} oc3_regs_t; - - -/* set/get OC-3 regs command opcode */ - -typedef struct oc3_opcode { - BITFIELD4( - enum opcode opcode : 8, /* cp opcode */ - u32 reg : 8, /* register index */ - u32 value : 8, /* register value */ - u32 mask : 8 /* register mask that specifies which - bits of the register value field - are significant */ - ) -} oc3_opcode_t; - - -/* set/get OC-3 regs command block */ - -typedef struct oc3_block { - struct oc3_opcode opcode; /* set/get OC-3 regs command opcode */ - u32 regs_haddr; /* host DMA address of OC-3 regs buffer */ -} oc3_block_t; - - -/* physical encoding statistics */ - -typedef struct stats_phy { - __be32 crc_header_errors; /* cells received with bad header CRC */ - __be32 framing_errors; /* cells received with bad framing */ - __be32 pad[ 2 ]; /* i960 padding */ -} stats_phy_t; - - -/* OC-3 statistics */ - -typedef struct stats_oc3 { - __be32 section_bip8_errors; /* section 8 bit interleaved parity */ - __be32 path_bip8_errors; /* path 8 bit interleaved parity */ - __be32 line_bip24_errors; /* line 24 bit interleaved parity */ - __be32 line_febe_errors; /* line far end block errors */ - __be32 path_febe_errors; /* path far end block errors */ - __be32 corr_hcs_errors; /* correctable header check sequence */ - __be32 ucorr_hcs_errors; /* uncorrectable header check sequence */ - __be32 pad[ 1 ]; /* i960 padding */ -} stats_oc3_t; - - -/* ATM statistics */ - -typedef struct stats_atm { - __be32 cells_transmitted; /* cells transmitted */ - __be32 cells_received; /* cells received */ - __be32 vpi_bad_range; /* cell drops: VPI out of range */ - __be32 vpi_no_conn; /* cell drops: no connection for VPI */ - __be32 vci_bad_range; /* cell drops: VCI out of range */ - __be32 vci_no_conn; /* cell drops: no connection for VCI */ - __be32 pad[ 2 ]; /* i960 padding */ -} stats_atm_t; - -/* AAL0 statistics */ - -typedef struct stats_aal0 { - __be32 cells_transmitted; /* cells transmitted */ - __be32 cells_received; /* cells received */ - __be32 cells_dropped; /* cells dropped */ - __be32 pad[ 1 ]; /* i960 padding */ -} stats_aal0_t; - - -/* AAL3/4 statistics */ - -typedef struct stats_aal34 { - __be32 cells_transmitted; /* cells transmitted from segmented PDUs */ - __be32 cells_received; /* cells reassembled into PDUs */ - __be32 cells_crc_errors; /* payload CRC error count */ - __be32 cells_protocol_errors; /* SAR or CS layer protocol errors */ - __be32 cells_dropped; /* cells dropped: partial reassembly */ - __be32 cspdus_transmitted; /* CS PDUs transmitted */ - __be32 cspdus_received; /* CS PDUs received */ - __be32 cspdus_protocol_errors; /* CS layer protocol errors */ - __be32 cspdus_dropped; /* reassembled PDUs drop'd (in cells) */ - __be32 pad[ 3 ]; /* i960 padding */ -} stats_aal34_t; - - -/* AAL5 statistics */ - -typedef struct stats_aal5 { - __be32 cells_transmitted; /* cells transmitted from segmented SDUs */ - __be32 cells_received; /* cells reassembled into SDUs */ - __be32 cells_dropped; /* reassembled PDUs dropped (in cells) */ - __be32 congestion_experienced; /* CRC error and length wrong */ - __be32 cspdus_transmitted; /* CS PDUs transmitted */ - __be32 cspdus_received; /* CS PDUs received */ - __be32 cspdus_crc_errors; /* CS PDUs CRC errors */ - __be32 cspdus_protocol_errors; /* CS layer protocol errors */ - __be32 cspdus_dropped; /* reassembled PDUs dropped */ - __be32 pad[ 3 ]; /* i960 padding */ -} stats_aal5_t; - - -/* auxiliary statistics */ - -typedef struct stats_aux { - __be32 small_b1_failed; /* receive BD allocation failures */ - __be32 large_b1_failed; /* receive BD allocation failures */ - __be32 small_b2_failed; /* receive BD allocation failures */ - __be32 large_b2_failed; /* receive BD allocation failures */ - __be32 rpd_alloc_failed; /* receive PDU allocation failures */ - __be32 receive_carrier; /* no carrier = 0, carrier = 1 */ - __be32 pad[ 2 ]; /* i960 padding */ -} stats_aux_t; - - -/* whole statistics buffer */ - -typedef struct stats { - struct stats_phy phy; /* physical encoding statistics */ - struct stats_oc3 oc3; /* OC-3 statistics */ - struct stats_atm atm; /* ATM statistics */ - struct stats_aal0 aal0; /* AAL0 statistics */ - struct stats_aal34 aal34; /* AAL3/4 statistics */ - struct stats_aal5 aal5; /* AAL5 statistics */ - struct stats_aux aux; /* auxiliary statistics */ -} stats_t; - - -/* get statistics command opcode */ - -typedef struct stats_opcode { - BITFIELD2( - enum opcode opcode : 8, /* cp opcode */ - u32 pad : 24 /* reserved */ - ) -} stats_opcode_t; - - -/* get statistics command block */ - -typedef struct stats_block { - struct stats_opcode opcode; /* get statistics command opcode */ - u32 stats_haddr; /* host DMA address of stats buffer */ -} stats_block_t; - - -/* expansion PROM data (PCI specific) */ - -typedef struct prom_data { - u32 hw_revision; /* hardware revision */ - u32 serial_number; /* board serial number */ - u8 mac_addr[ 8 ]; /* board MAC address */ -} prom_data_t; - - -/* get expansion PROM data command opcode */ - -typedef struct prom_opcode { - BITFIELD2( - enum opcode opcode : 8, /* cp opcode */ - u32 pad : 24 /* reserved */ - ) -} prom_opcode_t; - - -/* get expansion PROM data command block */ - -typedef struct prom_block { - struct prom_opcode opcode; /* get PROM data command opcode */ - u32 prom_haddr; /* host DMA address of PROM buffer */ -} prom_block_t; - - -/* cp command */ - -typedef union cmd { - enum opcode opcode; /* operation code */ - struct activate_block activate_block; /* activate VC */ - struct deactivate_block deactivate_block; /* deactivate VC */ - struct stats_block stats_block; /* get statistics */ - struct prom_block prom_block; /* get expansion PROM data */ - struct oc3_block oc3_block; /* get/set OC-3 registers */ - u32 pad[ 4 ]; /* i960 padding */ -} cmd_t; - - -/* cp resident command queue */ - -typedef struct cp_cmdq_entry { - union cmd cmd; /* command */ - u32 status_haddr; /* host DMA address of completion status */ - u32 pad[ 3 ]; /* i960 padding */ -} cp_cmdq_entry_t; - - -/* host resident transmit queue entry */ - -typedef struct host_txq_entry { - struct cp_txq_entry __iomem *cp_entry; /* addr of cp resident tx queue entry */ - enum status* status; /* addr of host resident status */ - struct tpd* tpd; /* addr of transmit PDU descriptor */ - u32 tpd_dma; /* DMA address of tpd */ - struct sk_buff* skb; /* related skb */ - void* data; /* copy of misaligned data */ - unsigned long incarn; /* vc_map incarnation when submitted for tx */ - struct fore200e_vc_map* vc_map; - -} host_txq_entry_t; - - -/* host resident receive queue entry */ - -typedef struct host_rxq_entry { - struct cp_rxq_entry __iomem *cp_entry; /* addr of cp resident rx queue entry */ - enum status* status; /* addr of host resident status */ - struct rpd* rpd; /* addr of receive PDU descriptor */ - u32 rpd_dma; /* DMA address of rpd */ -} host_rxq_entry_t; - - -/* host resident buffer supply queue entry */ - -typedef struct host_bsq_entry { - struct cp_bsq_entry __iomem *cp_entry; /* addr of cp resident buffer supply queue entry */ - enum status* status; /* addr of host resident status */ - struct rbd_block* rbd_block; /* addr of receive buffer descriptor block */ - u32 rbd_block_dma; /* DMA address od rdb */ -} host_bsq_entry_t; - - -/* host resident command queue entry */ - -typedef struct host_cmdq_entry { - struct cp_cmdq_entry __iomem *cp_entry; /* addr of cp resident cmd queue entry */ - enum status *status; /* addr of host resident status */ -} host_cmdq_entry_t; - - -/* chunk of memory */ - -typedef struct chunk { - void* alloc_addr; /* base address of allocated chunk */ - void* align_addr; /* base address of aligned chunk */ - dma_addr_t dma_addr; /* DMA address of aligned chunk */ - int direction; /* direction of DMA mapping */ - u32 alloc_size; /* length of allocated chunk */ - u32 align_size; /* length of aligned chunk */ -} chunk_t; - -#define dma_size align_size /* DMA useable size */ - - -/* host resident receive buffer */ - -typedef struct buffer { - struct buffer* next; /* next receive buffer */ - enum buffer_scheme scheme; /* buffer scheme */ - enum buffer_magn magn; /* buffer magnitude */ - struct chunk data; /* data buffer */ -#ifdef FORE200E_BSQ_DEBUG - unsigned long index; /* buffer # in queue */ - int supplied; /* 'buffer supplied' flag */ -#endif -} buffer_t; - - -#if (BITS_PER_LONG == 32) -#define FORE200E_BUF2HDL(buffer) ((u32)(buffer)) -#define FORE200E_HDL2BUF(handle) ((struct buffer*)(handle)) -#else /* deal with 64 bit pointers */ -#define FORE200E_BUF2HDL(buffer) ((u32)((u64)(buffer))) -#define FORE200E_HDL2BUF(handle) ((struct buffer*)(((u64)(handle)) | PAGE_OFFSET)) -#endif - - -/* host resident command queue */ - -typedef struct host_cmdq { - struct host_cmdq_entry host_entry[ QUEUE_SIZE_CMD ]; /* host resident cmd queue entries */ - int head; /* head of cmd queue */ - struct chunk status; /* array of completion status */ -} host_cmdq_t; - - -/* host resident transmit queue */ - -typedef struct host_txq { - struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ - int head; /* head of tx queue */ - int tail; /* tail of tx queue */ - struct chunk tpd; /* array of tpds */ - struct chunk status; /* arry of completion status */ - int txing; /* number of pending PDUs in tx queue */ -} host_txq_t; - - -/* host resident receive queue */ - -typedef struct host_rxq { - struct host_rxq_entry host_entry[ QUEUE_SIZE_RX ]; /* host resident rx queue entries */ - int head; /* head of rx queue */ - struct chunk rpd; /* array of rpds */ - struct chunk status; /* array of completion status */ -} host_rxq_t; - - -/* host resident buffer supply queues */ - -typedef struct host_bsq { - struct host_bsq_entry host_entry[ QUEUE_SIZE_BS ]; /* host resident buffer supply queue entries */ - int head; /* head of buffer supply queue */ - struct chunk rbd_block; /* array of rbds */ - struct chunk status; /* array of completion status */ - struct buffer* buffer; /* array of rx buffers */ - struct buffer* freebuf; /* list of free rx buffers */ - volatile int freebuf_count; /* count of free rx buffers */ -} host_bsq_t; - - -/* header of the firmware image */ - -typedef struct fw_header { - __le32 magic; /* magic number */ - __le32 version; /* firmware version id */ - __le32 load_offset; /* fw load offset in board memory */ - __le32 start_offset; /* fw execution start address in board memory */ -} fw_header_t; - -#define FW_HEADER_MAGIC 0x65726f66 /* 'fore' */ - - -/* receive buffer supply queues scheme specification */ - -typedef struct bs_spec { - u32 queue_length; /* queue capacity */ - u32 buffer_size; /* host buffer size */ - u32 pool_size; /* number of rbds */ - u32 supply_blksize; /* num of rbds in I/O block (multiple - of 4 between 4 and 124 inclusive) */ -} bs_spec_t; - - -/* initialization command block (one-time command, not in cmd queue) */ - -typedef struct init_block { - enum opcode opcode; /* initialize command */ - enum status status; /* related status word */ - u32 receive_threshold; /* not used */ - u32 num_connect; /* ATM connections */ - u32 cmd_queue_len; /* length of command queue */ - u32 tx_queue_len; /* length of transmit queue */ - u32 rx_queue_len; /* length of receive queue */ - u32 rsd_extension; /* number of extra 32 byte blocks */ - u32 tsd_extension; /* number of extra 32 byte blocks */ - u32 conless_vpvc; /* not used */ - u32 pad[ 2 ]; /* force quad alignment */ - struct bs_spec bs_spec[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues spec */ -} init_block_t; - - -typedef enum media_type { - MEDIA_TYPE_CAT5_UTP = 0x06, /* unshielded twisted pair */ - MEDIA_TYPE_MM_OC3_ST = 0x16, /* multimode fiber ST */ - MEDIA_TYPE_MM_OC3_SC = 0x26, /* multimode fiber SC */ - MEDIA_TYPE_SM_OC3_ST = 0x36, /* single-mode fiber ST */ - MEDIA_TYPE_SM_OC3_SC = 0x46 /* single-mode fiber SC */ -} media_type_t; - -#define FORE200E_MEDIA_INDEX(media_type) ((media_type)>>4) - - -/* cp resident queues */ - -typedef struct cp_queues { - u32 cp_cmdq; /* command queue */ - u32 cp_txq; /* transmit queue */ - u32 cp_rxq; /* receive queue */ - u32 cp_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; /* buffer supply queues */ - u32 imask; /* 1 enables cp to host interrupts */ - u32 istat; /* 1 for interrupt posted */ - u32 heap_base; /* offset form beginning of ram */ - u32 heap_size; /* space available for queues */ - u32 hlogger; /* non zero for host logging */ - u32 heartbeat; /* cp heartbeat */ - u32 fw_release; /* firmware version */ - u32 mon960_release; /* i960 monitor version */ - u32 tq_plen; /* transmit throughput measurements */ - /* make sure the init block remains on a quad word boundary */ - struct init_block init; /* one time cmd, not in cmd queue */ - enum media_type media_type; /* media type id */ - u32 oc3_revision; /* OC-3 revision number */ -} cp_queues_t; - - -/* boot status */ - -typedef enum boot_status { - BSTAT_COLD_START = (u32) 0xc01dc01d, /* cold start */ - BSTAT_SELFTEST_OK = (u32) 0x02201958, /* self-test ok */ - BSTAT_SELFTEST_FAIL = (u32) 0xadbadbad, /* self-test failed */ - BSTAT_CP_RUNNING = (u32) 0xce11feed, /* cp is running */ - BSTAT_MON_TOO_BIG = (u32) 0x10aded00 /* i960 monitor is too big */ -} boot_status_t; - - -/* software UART */ - -typedef struct soft_uart { - u32 send; /* write register */ - u32 recv; /* read register */ -} soft_uart_t; - -#define FORE200E_CP_MONITOR_UART_FREE 0x00000000 -#define FORE200E_CP_MONITOR_UART_AVAIL 0x01000000 - - -/* i960 monitor */ - -typedef struct cp_monitor { - struct soft_uart soft_uart; /* software UART */ - enum boot_status bstat; /* boot status */ - u32 app_base; /* application base offset */ - u32 mon_version; /* i960 monitor version */ -} cp_monitor_t; - - -/* device state */ - -typedef enum fore200e_state { - FORE200E_STATE_BLANK, /* initial state */ - FORE200E_STATE_REGISTER, /* device registered */ - FORE200E_STATE_CONFIGURE, /* bus interface configured */ - FORE200E_STATE_MAP, /* board space mapped in host memory */ - FORE200E_STATE_RESET, /* board resetted */ - FORE200E_STATE_START_FW, /* firmware started */ - FORE200E_STATE_INITIALIZE, /* initialize command successful */ - FORE200E_STATE_INIT_CMDQ, /* command queue initialized */ - FORE200E_STATE_INIT_TXQ, /* transmit queue initialized */ - FORE200E_STATE_INIT_RXQ, /* receive queue initialized */ - FORE200E_STATE_INIT_BSQ, /* buffer supply queue initialized */ - FORE200E_STATE_ALLOC_BUF, /* receive buffers allocated */ - FORE200E_STATE_IRQ, /* host interrupt requested */ - FORE200E_STATE_COMPLETE /* initialization completed */ -} fore200e_state; - - -/* PCA-200E registers */ - -typedef struct fore200e_pca_regs { - volatile u32 __iomem * hcr; /* address of host control register */ - volatile u32 __iomem * imr; /* address of host interrupt mask register */ - volatile u32 __iomem * psr; /* address of PCI specific register */ -} fore200e_pca_regs_t; - - -/* SBA-200E registers */ - -typedef struct fore200e_sba_regs { - u32 __iomem *hcr; /* address of host control register */ - u32 __iomem *bsr; /* address of burst transfer size register */ - u32 __iomem *isr; /* address of interrupt level selection register */ -} fore200e_sba_regs_t; - - -/* model-specific registers */ - -typedef union fore200e_regs { - struct fore200e_pca_regs pca; /* PCA-200E registers */ - struct fore200e_sba_regs sba; /* SBA-200E registers */ -} fore200e_regs; - - -struct fore200e; - -/* bus-dependent data */ - -typedef struct fore200e_bus { - char* model_name; /* board model name */ - char* proc_name; /* board name under /proc/atm */ - int descr_alignment; /* tpd/rpd/rbd DMA alignment requirement */ - int buffer_alignment; /* rx buffers DMA alignment requirement */ - int status_alignment; /* status words DMA alignment requirement */ - u32 (*read)(volatile u32 __iomem *); - void (*write)(u32, volatile u32 __iomem *); - int (*configure)(struct fore200e*); - int (*map)(struct fore200e*); - void (*reset)(struct fore200e*); - int (*prom_read)(struct fore200e*, struct prom_data*); - void (*unmap)(struct fore200e*); - void (*irq_enable)(struct fore200e*); - int (*irq_check)(struct fore200e*); - void (*irq_ack)(struct fore200e*); - int (*proc_read)(struct fore200e*, char*); -} fore200e_bus_t; - -/* vc mapping */ - -typedef struct fore200e_vc_map { - struct atm_vcc* vcc; /* vcc entry */ - unsigned long incarn; /* vcc incarnation number */ -} fore200e_vc_map_t; - -#define FORE200E_VC_MAP(fore200e, vpi, vci) \ - (& (fore200e)->vc_map[ ((vpi) << FORE200E_VCI_BITS) | (vci) ]) - - -/* per-device data */ - -typedef struct fore200e { - const struct fore200e_bus* bus; /* bus-dependent code and data */ - union fore200e_regs regs; /* bus-dependent registers */ - struct atm_dev* atm_dev; /* ATM device */ - - enum fore200e_state state; /* device state */ - - char name[16]; /* device name */ - struct device *dev; - int irq; /* irq number */ - unsigned long phys_base; /* physical base address */ - void __iomem * virt_base; /* virtual base address */ - - unsigned char esi[ ESI_LEN ]; /* end system identifier */ - - struct cp_monitor __iomem * cp_monitor; /* i960 monitor address */ - struct cp_queues __iomem * cp_queues; /* cp resident queues */ - struct host_cmdq host_cmdq; /* host resident cmd queue */ - struct host_txq host_txq; /* host resident tx queue */ - struct host_rxq host_rxq; /* host resident rx queue */ - /* host resident buffer supply queues */ - struct host_bsq host_bsq[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ]; - - u32 available_cell_rate; /* remaining pseudo-CBR bw on link */ - - int loop_mode; /* S/UNI loopback mode */ - - struct stats* stats; /* last snapshot of the stats */ - - struct mutex rate_mtx; /* protects rate reservation ops */ - spinlock_t q_lock; /* protects queue ops */ -#ifdef FORE200E_USE_TASKLET - struct tasklet_struct tx_tasklet; /* performs tx interrupt work */ - struct tasklet_struct rx_tasklet; /* performs rx interrupt work */ -#endif - unsigned long tx_sat; /* tx queue saturation count */ - - unsigned long incarn_count; - struct fore200e_vc_map vc_map[ NBR_CONNECT ]; /* vc mapping */ -} fore200e_t; - - -/* per-vcc data */ - -typedef struct fore200e_vcc { - enum buffer_scheme scheme; /* rx buffer scheme */ - struct tpd_rate rate; /* tx rate control data */ - int rx_min_pdu; /* size of smallest PDU received */ - int rx_max_pdu; /* size of largest PDU received */ - int tx_min_pdu; /* size of smallest PDU transmitted */ - int tx_max_pdu; /* size of largest PDU transmitted */ - unsigned long tx_pdu; /* nbr of tx pdus */ - unsigned long rx_pdu; /* nbr of rx pdus */ -} fore200e_vcc_t; - - - -/* 200E-series common memory layout */ - -#define FORE200E_CP_MONITOR_OFFSET 0x00000400 /* i960 monitor interface */ -#define FORE200E_CP_QUEUES_OFFSET 0x00004d40 /* cp resident queues */ - - -/* PCA-200E memory layout */ - -#define PCA200E_IOSPACE_LENGTH 0x00200000 - -#define PCA200E_HCR_OFFSET 0x00100000 /* board control register */ -#define PCA200E_IMR_OFFSET 0x00100004 /* host IRQ mask register */ -#define PCA200E_PSR_OFFSET 0x00100008 /* PCI specific register */ - - -/* PCA-200E host control register */ - -#define PCA200E_HCR_RESET (1<<0) /* read / write */ -#define PCA200E_HCR_HOLD_LOCK (1<<1) /* read / write */ -#define PCA200E_HCR_I960FAIL (1<<2) /* read */ -#define PCA200E_HCR_INTRB (1<<2) /* write */ -#define PCA200E_HCR_HOLD_ACK (1<<3) /* read */ -#define PCA200E_HCR_INTRA (1<<3) /* write */ -#define PCA200E_HCR_OUTFULL (1<<4) /* read */ -#define PCA200E_HCR_CLRINTR (1<<4) /* write */ -#define PCA200E_HCR_ESPHOLD (1<<5) /* read */ -#define PCA200E_HCR_INFULL (1<<6) /* read */ -#define PCA200E_HCR_TESTMODE (1<<7) /* read */ - - -/* PCA-200E PCI bus interface regs (offsets in PCI config space) */ - -#define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ -#define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ -#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continuous req threshold */ - -/* PBI master control register */ - -#define PCA200E_CTRL_DIS_CACHE_RD (1<<0) /* disable cache-line reads */ -#define PCA200E_CTRL_DIS_WRT_INVAL (1<<1) /* disable writes and invalidates */ -#define PCA200E_CTRL_2_CACHE_WRT_INVAL (1<<2) /* require 2 cache-lines for writes and invalidates */ -#define PCA200E_CTRL_IGN_LAT_TIMER (1<<3) /* ignore the latency timer */ -#define PCA200E_CTRL_ENA_CONT_REQ_MODE (1<<4) /* enable continuous request mode */ -#define PCA200E_CTRL_LARGE_PCI_BURSTS (1<<5) /* force large PCI bus bursts */ -#define PCA200E_CTRL_CONVERT_ENDIAN (1<<6) /* convert endianess of slave RAM accesses */ - - - -#define SBA200E_PROM_NAME "FORE,sba-200e" /* device name in openprom tree */ - - -/* size of SBA-200E registers */ - -#define SBA200E_HCR_LENGTH 4 -#define SBA200E_BSR_LENGTH 4 -#define SBA200E_ISR_LENGTH 4 -#define SBA200E_RAM_LENGTH 0x40000 - - -/* SBA-200E SBUS burst transfer size register */ - -#define SBA200E_BSR_BURST4 0x04 -#define SBA200E_BSR_BURST8 0x08 -#define SBA200E_BSR_BURST16 0x10 - - -/* SBA-200E host control register */ - -#define SBA200E_HCR_RESET (1<<0) /* read / write (sticky) */ -#define SBA200E_HCR_HOLD_LOCK (1<<1) /* read / write (sticky) */ -#define SBA200E_HCR_I960FAIL (1<<2) /* read */ -#define SBA200E_HCR_I960SETINTR (1<<2) /* write */ -#define SBA200E_HCR_OUTFULL (1<<3) /* read */ -#define SBA200E_HCR_INTR_CLR (1<<3) /* write */ -#define SBA200E_HCR_INTR_ENA (1<<4) /* read / write (sticky) */ -#define SBA200E_HCR_ESPHOLD (1<<5) /* read */ -#define SBA200E_HCR_INFULL (1<<6) /* read */ -#define SBA200E_HCR_TESTMODE (1<<7) /* read */ -#define SBA200E_HCR_INTR_REQ (1<<8) /* read */ - -#define SBA200E_HCR_STICKY (SBA200E_HCR_RESET | SBA200E_HCR_HOLD_LOCK | SBA200E_HCR_INTR_ENA) - - -#endif /* __KERNEL__ */ -#endif /* _FORE200E_H */ diff --git a/drivers/atm/he.h b/drivers/atm/he.h deleted file mode 100644 index f3f53674ef3f..000000000000 --- a/drivers/atm/he.h +++ /dev/null @@ -1,845 +0,0 @@ -/* - - he.h - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2001 Naval Research Laboratory - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/* - - he.h - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2000 Naval Research Laboratory - - Permission to use, copy, modify and distribute this software and its - documentation is hereby granted, provided that both the copyright - notice and this permission notice appear in all copies of the software, - derivative works or modified versions, and any portions thereof, and - that both notices appear in supporting documentation. - - NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND - DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER - RESULTING FROM THE USE OF THIS SOFTWARE. - - */ - -#ifndef _HE_H_ -#define _HE_H_ - -#define DEV_LABEL "he" - -#define CONFIG_DEFAULT_VCIBITS 12 -#define CONFIG_DEFAULT_VPIBITS 0 - -#define CONFIG_IRQ_SIZE 128 -#define CONFIG_IRQ_THRESH (CONFIG_IRQ_SIZE/2) - -#define CONFIG_TPDRQ_SIZE 512 -#define TPDRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TPDRQ_SIZE<<3)-1)) - -#define CONFIG_RBRQ_SIZE 512 -#define CONFIG_RBRQ_THRESH 400 -#define RBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_RBRQ_SIZE<<3)-1)) - -#define CONFIG_TBRQ_SIZE 512 -#define CONFIG_TBRQ_THRESH 400 -#define TBRQ_MASK(x) (((unsigned long)(x))&((CONFIG_TBRQ_SIZE<<2)-1)) - -#define CONFIG_RBPL_SIZE 512 -#define CONFIG_RBPL_THRESH 64 -#define CONFIG_RBPL_BUFSIZE 4096 -#define RBPL_MASK(x) (((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1)) - -/* 5.1.3 initialize connection memory */ - -#define CONFIG_RSRA 0x00000 -#define CONFIG_RCMLBM 0x08000 -#define CONFIG_RCMABR 0x0d800 -#define CONFIG_RSRB 0x0e000 - -#define CONFIG_TSRA 0x00000 -#define CONFIG_TSRB 0x08000 -#define CONFIG_TSRC 0x0c000 -#define CONFIG_TSRD 0x0e000 -#define CONFIG_TMABR 0x0f000 -#define CONFIG_TPDBA 0x10000 - -#define HE_MAXCIDBITS 12 - -/* 2.9.3.3 interrupt encodings */ - -struct he_irq { - volatile u32 isw; -}; - -#define IRQ_ALIGNMENT 0x1000 - -#define NEXT_ENTRY(base, tail, mask) \ - (((unsigned long)base)|(((unsigned long)(tail+1))&mask)) - -#define ITYPE_INVALID 0xffffffff -#define ITYPE_TBRQ_THRESH (0<<3) -#define ITYPE_TPD_COMPLETE (1<<3) -#define ITYPE_RBPS_THRESH (2<<3) -#define ITYPE_RBPL_THRESH (3<<3) -#define ITYPE_RBRQ_THRESH (4<<3) -#define ITYPE_RBRQ_TIMER (5<<3) -#define ITYPE_PHY (6<<3) -#define ITYPE_OTHER 0x80 -#define ITYPE_PARITY 0x81 -#define ITYPE_ABORT 0x82 - -#define ITYPE_GROUP(x) (x & 0x7) -#define ITYPE_TYPE(x) (x & 0xf8) - -#define HE_NUM_GROUPS 8 - -/* 2.1.4 transmit packet descriptor */ - -struct he_tpd { - - /* read by the adapter */ - - volatile u32 status; - volatile u32 reserved; - -#define TPD_MAXIOV 3 - struct { - u32 addr, len; - } iovec[TPD_MAXIOV]; - -#define address0 iovec[0].addr -#define length0 iovec[0].len - - /* linux-atm extensions */ - - struct sk_buff *skb; - struct atm_vcc *vcc; - - struct list_head entry; -}; - -#define TPD_ALIGNMENT 64 -#define TPD_LEN_MASK 0xffff - -#define TPD_ADDR_SHIFT 6 -#define TPD_MASK 0xffffffc0 -#define TPD_ADDR(x) ((x) & TPD_MASK) -#define TPD_INDEX(x) (TPD_ADDR(x) >> TPD_ADDR_SHIFT) - - -/* table 2.3 transmit buffer return elements */ - -struct he_tbrq { - volatile u32 tbre; -}; - -#define TBRQ_ALIGNMENT CONFIG_TBRQ_SIZE - -#define TBRQ_TPD(tbrq) ((tbrq)->tbre & 0xffffffc0) -#define TBRQ_EOS(tbrq) ((tbrq)->tbre & (1<<3)) -#define TBRQ_MULTIPLE(tbrq) ((tbrq)->tbre & (1)) - -/* table 2.21 receive buffer return queue element field organization */ - -struct he_rbrq { - volatile u32 addr; - volatile u32 cidlen; -}; - -#define RBRQ_ALIGNMENT CONFIG_RBRQ_SIZE - -#define RBRQ_ADDR(rbrq) ((rbrq)->addr & 0xffffffc0) -#define RBRQ_CRC_ERR(rbrq) ((rbrq)->addr & (1<<5)) -#define RBRQ_LEN_ERR(rbrq) ((rbrq)->addr & (1<<4)) -#define RBRQ_END_PDU(rbrq) ((rbrq)->addr & (1<<3)) -#define RBRQ_AAL5_PROT(rbrq) ((rbrq)->addr & (1<<2)) -#define RBRQ_CON_CLOSED(rbrq) ((rbrq)->addr & (1<<1)) -#define RBRQ_HBUF_ERR(rbrq) ((rbrq)->addr & 1) -#define RBRQ_CID(rbrq) (((rbrq)->cidlen >> 16) & 0x1fff) -#define RBRQ_BUFLEN(rbrq) ((rbrq)->cidlen & 0xffff) - -/* figure 2.3 transmit packet descriptor ready queue */ - -struct he_tpdrq { - volatile u32 tpd; - volatile u32 cid; -}; - -#define TPDRQ_ALIGNMENT CONFIG_TPDRQ_SIZE - -/* table 2.30 host status page detail */ - -#define HSP_ALIGNMENT 0x400 /* must align on 1k boundary */ - -struct he_hsp { - struct he_hsp_entry { - volatile u32 tbrq_tail; - volatile u32 reserved1[15]; - volatile u32 rbrq_tail; - volatile u32 reserved2[15]; - } group[HE_NUM_GROUPS]; -}; - -/* - * figure 2.9 receive buffer pools - * - * since a virtual address might be more than 32 bits, we store an index - * in the virt member of he_rbp. NOTE: the lower six bits in the rbrq - * addr member are used for buffer status further limiting us to 26 bits. - */ - -struct he_rbp { - volatile u32 phys; - volatile u32 idx; /* virt */ -}; - -#define RBP_IDX_OFFSET 6 - -/* - * the he dma engine will try to hold an extra 16 buffers in its local - * caches. and add a couple buffers for safety. - */ - -#define RBPL_TABLE_SIZE (CONFIG_RBPL_SIZE + 16 + 2) - -struct he_buff { - struct list_head entry; - dma_addr_t mapping; - unsigned long len; - u8 data[]; -}; - -#ifdef notyet -struct he_group { - u32 rpbl_size, rpbl_qsize; - struct he_rpb_entry *rbpl_ba; -}; -#endif - -#define HE_LOOKUP_VCC(dev, cid) ((dev)->he_vcc_table[(cid)].vcc) - -struct he_vcc_table -{ - struct atm_vcc *vcc; -}; - -struct he_cs_stper -{ - long pcr; - int inuse; -}; - -#define HE_NUM_CS_STPER 16 - -struct he_dev { - unsigned int number; - unsigned int irq; - void __iomem *membase; - - char prod_id[30]; - char mac_addr[6]; - int media; - - unsigned int vcibits, vpibits; - unsigned int cells_per_row; - unsigned int bytes_per_row; - unsigned int cells_per_lbuf; - unsigned int r0_numrows, r0_startrow, r0_numbuffs; - unsigned int r1_numrows, r1_startrow, r1_numbuffs; - unsigned int tx_numrows, tx_startrow, tx_numbuffs; - unsigned int buffer_limit; - - struct he_vcc_table *he_vcc_table; - -#ifdef notyet - struct he_group group[HE_NUM_GROUPS]; -#endif - struct he_cs_stper cs_stper[HE_NUM_CS_STPER]; - unsigned total_bw; - - dma_addr_t irq_phys; - struct he_irq *irq_base, *irq_head, *irq_tail; - volatile unsigned *irq_tailoffset; - int irq_peak; - - struct tasklet_struct tasklet; - struct dma_pool *tpd_pool; - struct list_head outstanding_tpds; - - dma_addr_t tpdrq_phys; - struct he_tpdrq *tpdrq_base, *tpdrq_tail, *tpdrq_head; - - spinlock_t global_lock; /* 8.1.5 pci transaction ordering - error problem */ - dma_addr_t rbrq_phys; - struct he_rbrq *rbrq_base, *rbrq_head; - int rbrq_peak; - - struct he_buff **rbpl_virt; - unsigned long *rbpl_table; - unsigned long rbpl_hint; - struct dma_pool *rbpl_pool; - dma_addr_t rbpl_phys; - struct he_rbp *rbpl_base, *rbpl_tail; - struct list_head rbpl_outstanding; - int rbpl_peak; - - dma_addr_t tbrq_phys; - struct he_tbrq *tbrq_base, *tbrq_head; - int tbrq_peak; - - dma_addr_t hsp_phys; - struct he_hsp *hsp; - - struct pci_dev *pci_dev; - struct atm_dev *atm_dev; - struct he_dev *next; -}; - -#define HE_MAXIOV 20 - -struct he_vcc -{ - struct list_head buffers; - int pdu_len; - int rc_index; - - wait_queue_head_t rx_waitq; - wait_queue_head_t tx_waitq; -}; - -#define HE_VCC(vcc) ((struct he_vcc *)(vcc->dev_data)) - -#define PCI_VENDOR_ID_FORE 0x1127 -#define PCI_DEVICE_ID_FORE_HE 0x400 - -#define GEN_CNTL_0 0x40 -#define INT_PROC_ENBL (1<<25) -#define SLAVE_ENDIAN_MODE (1<<16) -#define MRL_ENB (1<<5) -#define MRM_ENB (1<<4) -#define INIT_ENB (1<<2) -#define IGNORE_TIMEOUT (1<<1) -#define ENBL_64 (1<<0) - -#define MIN_PCI_LATENCY 32 /* errata 8.1.3 */ - -#define HE_DEV(dev) ((struct he_dev *) (dev)->dev_data) - -#define he_is622(dev) ((dev)->media & 0x1) -#define he_isMM(dev) ((dev)->media & 0x20) - -#define HE_REGMAP_SIZE 0x100000 - -#define RESET_CNTL 0x80000 -#define BOARD_RST_STATUS (1<<6) - -#define HOST_CNTL 0x80004 -#define PCI_BUS_SIZE64 (1<<27) -#define DESC_RD_STATIC_64 (1<<26) -#define DATA_RD_STATIC_64 (1<<25) -#define DATA_WR_STATIC_64 (1<<24) -#define ID_CS (1<<12) -#define ID_WREN (1<<11) -#define ID_DOUT (1<<10) -#define ID_DOFFSET 10 -#define ID_DIN (1<<9) -#define ID_CLOCK (1<<8) -#define QUICK_RD_RETRY (1<<7) -#define QUICK_WR_RETRY (1<<6) -#define OUTFF_ENB (1<<5) -#define CMDFF_ENB (1<<4) -#define PERR_INT_ENB (1<<2) -#define IGNORE_INTR (1<<0) - -#define LB_SWAP 0x80008 -#define SWAP_RNUM_MAX(x) (x<<27) -#define DATA_WR_SWAP (1<<20) -#define DESC_RD_SWAP (1<<19) -#define DATA_RD_SWAP (1<<18) -#define INTR_SWAP (1<<17) -#define DESC_WR_SWAP (1<<16) -#define SDRAM_INIT (1<<15) -#define BIG_ENDIAN_HOST (1<<14) -#define XFER_SIZE (1<<7) - -#define LB_MEM_ADDR 0x8000c -#define LB_MEM_DATA 0x80010 - -#define LB_MEM_ACCESS 0x80014 -#define LB_MEM_HNDSHK (1<<30) -#define LM_MEM_WRITE (0x7) -#define LM_MEM_READ (0x3) - -#define SDRAM_CTL 0x80018 -#define LB_64_ENB (1<<3) -#define LB_TWR (1<<2) -#define LB_TRP (1<<1) -#define LB_TRAS (1<<0) - -#define INT_FIFO 0x8001c -#define INT_MASK_D (1<<15) -#define INT_MASK_C (1<<14) -#define INT_MASK_B (1<<13) -#define INT_MASK_A (1<<12) -#define INT_CLEAR_D (1<<11) -#define INT_CLEAR_C (1<<10) -#define INT_CLEAR_B (1<<9) -#define INT_CLEAR_A (1<<8) - -#define ABORT_ADDR 0x80020 - -#define IRQ0_BASE 0x80080 -#define IRQ_BASE(x) (x<<12) -#define IRQ_MASK ((CONFIG_IRQ_SIZE<<2)-1) /* was 0x3ff */ -#define IRQ_TAIL(x) (((unsigned long)(x)) & IRQ_MASK) -#define IRQ0_HEAD 0x80084 -#define IRQ_SIZE(x) (x<<22) -#define IRQ_THRESH(x) (x<<12) -#define IRQ_HEAD(x) (x<<2) -/* #define IRQ_PENDING (1) conflict with linux/irq.h */ -#define IRQ0_CNTL 0x80088 -#define IRQ_ADDRSEL(x) (x<<2) -#define IRQ_INT_A (0<<2) -#define IRQ_INT_B (1<<2) -#define IRQ_INT_C (2<<2) -#define IRQ_INT_D (3<<2) -#define IRQ_TYPE_ADDR 0x1 -#define IRQ_TYPE_LINE 0x0 -#define IRQ0_DATA 0x8008c - -#define IRQ1_BASE 0x80090 -#define IRQ1_HEAD 0x80094 -#define IRQ1_CNTL 0x80098 -#define IRQ1_DATA 0x8009c - -#define IRQ2_BASE 0x800a0 -#define IRQ2_HEAD 0x800a4 -#define IRQ2_CNTL 0x800a8 -#define IRQ2_DATA 0x800ac - -#define IRQ3_BASE 0x800b0 -#define IRQ3_HEAD 0x800b4 -#define IRQ3_CNTL 0x800b8 -#define IRQ3_DATA 0x800bc - -#define GRP_10_MAP 0x800c0 -#define GRP_32_MAP 0x800c4 -#define GRP_54_MAP 0x800c8 -#define GRP_76_MAP 0x800cc - -#define G0_RBPS_S 0x80400 -#define G0_RBPS_T 0x80404 -#define RBP_TAIL(x) ((x)<<3) -#define RBP_MASK(x) ((x)|0x1fff) -#define G0_RBPS_QI 0x80408 -#define RBP_QSIZE(x) ((x)<<14) -#define RBP_INT_ENB (1<<13) -#define RBP_THRESH(x) (x) -#define G0_RBPS_BS 0x8040c -#define G0_RBPL_S 0x80410 -#define G0_RBPL_T 0x80414 -#define G0_RBPL_QI 0x80418 -#define G0_RBPL_BS 0x8041c - -#define G1_RBPS_S 0x80420 -#define G1_RBPS_T 0x80424 -#define G1_RBPS_QI 0x80428 -#define G1_RBPS_BS 0x8042c -#define G1_RBPL_S 0x80430 -#define G1_RBPL_T 0x80434 -#define G1_RBPL_QI 0x80438 -#define G1_RBPL_BS 0x8043c - -#define G2_RBPS_S 0x80440 -#define G2_RBPS_T 0x80444 -#define G2_RBPS_QI 0x80448 -#define G2_RBPS_BS 0x8044c -#define G2_RBPL_S 0x80450 -#define G2_RBPL_T 0x80454 -#define G2_RBPL_QI 0x80458 -#define G2_RBPL_BS 0x8045c - -#define G3_RBPS_S 0x80460 -#define G3_RBPS_T 0x80464 -#define G3_RBPS_QI 0x80468 -#define G3_RBPS_BS 0x8046c -#define G3_RBPL_S 0x80470 -#define G3_RBPL_T 0x80474 -#define G3_RBPL_QI 0x80478 -#define G3_RBPL_BS 0x8047c - -#define G4_RBPS_S 0x80480 -#define G4_RBPS_T 0x80484 -#define G4_RBPS_QI 0x80488 -#define G4_RBPS_BS 0x8048c -#define G4_RBPL_S 0x80490 -#define G4_RBPL_T 0x80494 -#define G4_RBPL_QI 0x80498 -#define G4_RBPL_BS 0x8049c - -#define G5_RBPS_S 0x804a0 -#define G5_RBPS_T 0x804a4 -#define G5_RBPS_QI 0x804a8 -#define G5_RBPS_BS 0x804ac -#define G5_RBPL_S 0x804b0 -#define G5_RBPL_T 0x804b4 -#define G5_RBPL_QI 0x804b8 -#define G5_RBPL_BS 0x804bc - -#define G6_RBPS_S 0x804c0 -#define G6_RBPS_T 0x804c4 -#define G6_RBPS_QI 0x804c8 -#define G6_RBPS_BS 0x804cc -#define G6_RBPL_S 0x804d0 -#define G6_RBPL_T 0x804d4 -#define G6_RBPL_QI 0x804d8 -#define G6_RBPL_BS 0x804dc - -#define G7_RBPS_S 0x804e0 -#define G7_RBPS_T 0x804e4 -#define G7_RBPS_QI 0x804e8 -#define G7_RBPS_BS 0x804ec - -#define G7_RBPL_S 0x804f0 -#define G7_RBPL_T 0x804f4 -#define G7_RBPL_QI 0x804f8 -#define G7_RBPL_BS 0x804fc - -#define G0_RBRQ_ST 0x80500 -#define G0_RBRQ_H 0x80504 -#define G0_RBRQ_Q 0x80508 -#define RBRQ_THRESH(x) ((x)<<13) -#define RBRQ_SIZE(x) (x) -#define G0_RBRQ_I 0x8050c -#define RBRQ_TIME(x) ((x)<<8) -#define RBRQ_COUNT(x) (x) - -/* fill in 1 ... 7 later */ - -#define G0_TBRQ_B_T 0x80600 -#define G0_TBRQ_H 0x80604 -#define G0_TBRQ_S 0x80608 -#define G0_TBRQ_THRESH 0x8060c -#define TBRQ_THRESH(x) (x) - -/* fill in 1 ... 7 later */ - -#define RH_CONFIG 0x805c0 -#define PHY_INT_ENB (1<<10) -#define OAM_GID(x) (x<<7) -#define PTMR_PRE(x) (x) - -#define G0_INMQ_S 0x80580 -#define G0_INMQ_L 0x80584 -#define G1_INMQ_S 0x80588 -#define G1_INMQ_L 0x8058c -#define G2_INMQ_S 0x80590 -#define G2_INMQ_L 0x80594 -#define G3_INMQ_S 0x80598 -#define G3_INMQ_L 0x8059c -#define G4_INMQ_S 0x805a0 -#define G4_INMQ_L 0x805a4 -#define G5_INMQ_S 0x805a8 -#define G5_INMQ_L 0x805ac -#define G6_INMQ_S 0x805b0 -#define G6_INMQ_L 0x805b4 -#define G7_INMQ_S 0x805b8 -#define G7_INMQ_L 0x805bc - -#define TPDRQ_B_H 0x80680 -#define TPDRQ_T 0x80684 -#define TPDRQ_S 0x80688 - -#define UBUFF_BA 0x8068c - -#define RLBF0_H 0x806c0 -#define RLBF0_T 0x806c4 -#define RLBF1_H 0x806c8 -#define RLBF1_T 0x806cc -#define RLBC_H 0x806d0 -#define RLBC_T 0x806d4 -#define RLBC_H2 0x806d8 -#define TLBF_H 0x806e0 -#define TLBF_T 0x806e4 -#define RLBF0_C 0x806e8 -#define RLBF1_C 0x806ec -#define RXTHRSH 0x806f0 -#define LITHRSH 0x806f4 - -#define LBARB 0x80700 -#define SLICE_X(x) (x<<28) -#define ARB_RNUM_MAX(x) (x<<23) -#define TH_PRTY(x) (x<<21) -#define RH_PRTY(x) (x<<19) -#define TL_PRTY(x) (x<<17) -#define RL_PRTY(x) (x<<15) -#define BUS_MULTI(x) (x<<8) -#define NET_PREF(x) (x) - -#define SDRAMCON 0x80704 -#define BANK_ON (1<<14) -#define WIDE_DATA (1<<13) -#define TWR_WAIT (1<<12) -#define TRP_WAIT (1<<11) -#define TRAS_WAIT (1<<10) -#define REF_RATE(x) (x) - -#define LBSTAT 0x80708 - -#define RCC_STAT 0x8070c -#define RCC_BUSY (1) - -#define TCMCONFIG 0x80740 -#define TM_DESL2 (1<<10) -#define TM_BANK_WAIT(x) (x<<6) -#define TM_ADD_BANK4(x) (x<<4) -#define TM_PAR_CHECK(x) (x<<3) -#define TM_RW_WAIT(x) (x<<2) -#define TM_SRAM_TYPE(x) (x) - -#define TSRB_BA 0x80744 -#define TSRC_BA 0x80748 -#define TMABR_BA 0x8074c -#define TPD_BA 0x80750 -#define TSRD_BA 0x80758 - -#define TX_CONFIG 0x80760 -#define DRF_THRESH(x) (x<<22) -#define TX_UT_MODE(x) (x<<21) -#define TX_VCI_MASK(x) (x<<17) -#define LBFREE_CNT(x) (x) - -#define TXAAL5_PROTO 0x80764 -#define CPCS_UU(x) (x<<8) -#define CPI(x) (x) - -#define RCMCONFIG 0x80780 -#define RM_DESL2(x) (x<<10) -#define RM_BANK_WAIT(x) (x<<6) -#define RM_ADD_BANK(x) (x<<4) -#define RM_PAR_CHECK(x) (x<<3) -#define RM_RW_WAIT(x) (x<<2) -#define RM_SRAM_TYPE(x) (x) - -#define RCMRSRB_BA 0x80784 -#define RCMLBM_BA 0x80788 -#define RCMABR_BA 0x8078c - -#define RC_CONFIG 0x807c0 -#define UT_RD_DELAY(x) (x<<11) -#define WRAP_MODE(x) (x<<10) -#define RC_UT_MODE(x) (x<<9) -#define RX_ENABLE (1<<8) -#define RX_VALVP(x) (x<<4) -#define RX_VALVC(x) (x) - -#define MCC 0x807c4 -#define OEC 0x807c8 -#define DCC 0x807cc -#define CEC 0x807d0 - -#define HSP_BA 0x807f0 - -#define LB_CONFIG 0x807f4 -#define LB_SIZE(x) (x) - -#define CON_DAT 0x807f8 -#define CON_CTL 0x807fc -#define CON_CTL_MBOX (2<<30) -#define CON_CTL_TCM (1<<30) -#define CON_CTL_RCM (0<<30) -#define CON_CTL_WRITE (1<<29) -#define CON_CTL_READ (0<<29) -#define CON_CTL_BUSY (1<<28) -#define CON_BYTE_DISABLE_3 (1<<22) /* 24..31 */ -#define CON_BYTE_DISABLE_2 (1<<21) /* 16..23 */ -#define CON_BYTE_DISABLE_1 (1<<20) /* 8..15 */ -#define CON_BYTE_DISABLE_0 (1<<19) /* 0..7 */ -#define CON_CTL_ADDR(x) (x) - -#define FRAMER 0x80800 /* to 0x80bfc */ - -/* 3.3 network controller (internal) mailbox registers */ - -#define CS_STPER0 0x0 - /* ... */ -#define CS_STPER31 0x01f - -#define CS_STTIM0 0x020 - /* ... */ -#define CS_STTIM31 0x03f - -#define CS_TGRLD0 0x040 - /* ... */ -#define CS_TGRLD15 0x04f - -#define CS_ERTHR0 0x050 -#define CS_ERTHR1 0x051 -#define CS_ERTHR2 0x052 -#define CS_ERTHR3 0x053 -#define CS_ERTHR4 0x054 -#define CS_ERCTL0 0x055 -#define TX_ENABLE (1<<28) -#define ER_ENABLE (1<<27) -#define CS_ERCTL1 0x056 -#define CS_ERCTL2 0x057 -#define CS_ERSTAT0 0x058 -#define CS_ERSTAT1 0x059 - -#define CS_RTCCT 0x060 -#define CS_RTFWC 0x061 -#define CS_RTFWR 0x062 -#define CS_RTFTC 0x063 -#define CS_RTATR 0x064 - -#define CS_TFBSET 0x070 -#define CS_TFBADD 0x071 -#define CS_TFBSUB 0x072 -#define CS_WCRMAX 0x073 -#define CS_WCRMIN 0x074 -#define CS_WCRINC 0x075 -#define CS_WCRDEC 0x076 -#define CS_WCRCEIL 0x077 -#define CS_BWDCNT 0x078 - -#define CS_OTPPER 0x080 -#define CS_OTWPER 0x081 -#define CS_OTTLIM 0x082 -#define CS_OTTCNT 0x083 - -#define CS_HGRRT0 0x090 - /* ... */ -#define CS_HGRRT7 0x097 - -#define CS_ORPTRS 0x0a0 - -#define RXCON_CLOSE 0x100 - - -#define RCM_MEM_SIZE 0x10000 /* 1M of 32-bit registers */ -#define TCM_MEM_SIZE 0x20000 /* 2M of 32-bit registers */ - -/* 2.5 transmit connection memory registers */ - -#define TSR0_CONN_STATE(x) ((x>>28) & 0x7) -#define TSR0_USE_WMIN (1<<23) -#define TSR0_GROUP(x) ((x & 0x7)<<18) -#define TSR0_ABR (2<<16) -#define TSR0_UBR (1<<16) -#define TSR0_CBR (0<<16) -#define TSR0_PROT (1<<15) -#define TSR0_AAL0_SDU (2<<12) -#define TSR0_AAL0 (1<<12) -#define TSR0_AAL5 (0<<12) -#define TSR0_HALT_ER (1<<11) -#define TSR0_MARK_CI (1<<10) -#define TSR0_MARK_ER (1<<9) -#define TSR0_UPDATE_GER (1<<8) -#define TSR0_RC_INDEX(x) (x & 0x1F) - -#define TSR1_PCR(x) ((x & 0x7FFF)<<16) -#define TSR1_MCR(x) (x & 0x7FFF) - -#define TSR2_ACR(x) ((x & 0x7FFF)<<16) - -#define TSR3_NRM_CNT(x) ((x & 0xFF)<<24) -#define TSR3_CRM_CNT(x) (x & 0xFFFF) - -#define TSR4_FLUSH_CONN (1<<31) -#define TSR4_SESSION_ENDED (1<<30) -#define TSR4_CRC10 (1<<28) -#define TSR4_NULL_CRC10 (1<<27) -#define TSR4_PROT (1<<26) -#define TSR4_AAL0_SDU (2<<23) -#define TSR4_AAL0 (1<<23) -#define TSR4_AAL5 (0<<23) - -#define TSR9_OPEN_CONN (1<<20) - -#define TSR11_ICR(x) ((x & 0x7FFF)<<16) -#define TSR11_TRM(x) ((x & 0x7)<<13) -#define TSR11_NRM(x) ((x & 0x7)<<10) -#define TSR11_ADTF(x) (x & 0x3FF) - -#define TSR13_RDF(x) ((x & 0xF)<<23) -#define TSR13_RIF(x) ((x & 0xF)<<19) -#define TSR13_CDF(x) ((x & 0x7)<<16) -#define TSR13_CRM(x) (x & 0xFFFF) - -#define TSR14_DELETE (1<<31) -#define TSR14_ABR_CLOSE (1<<16) - -/* 2.7.1 per connection receieve state registers */ - -#define RSR0_START_PDU (1<<10) -#define RSR0_OPEN_CONN (1<<6) -#define RSR0_CLOSE_CONN (0<<6) -#define RSR0_PPD_ENABLE (1<<5) -#define RSR0_EPD_ENABLE (1<<4) -#define RSR0_TCP_CKSUM (1<<3) -#define RSR0_AAL5 (0) -#define RSR0_AAL0 (1) -#define RSR0_AAL0_SDU (2) -#define RSR0_RAWCELL (3) -#define RSR0_RAWCELL_CRC10 (4) - -#define RSR1_AQI_ENABLE (1<<20) -#define RSR1_RBPL_ONLY (1<<19) -#define RSR1_GROUP(x) ((x)<<16) - -#define RSR4_AQI_ENABLE (1<<30) -#define RSR4_GROUP(x) ((x)<<27) -#define RSR4_RBPL_ONLY (1<<26) - -/* 2.1.4 transmit packet descriptor */ - -#define TPD_USERCELL 0x0 -#define TPD_SEGMENT_OAMF5 0x4 -#define TPD_END2END_OAMF5 0x5 -#define TPD_RMCELL 0x6 -#define TPD_CELLTYPE(x) (x<<3) -#define TPD_EOS (1<<2) -#define TPD_CLP (1<<1) -#define TPD_INT (1<<0) -#define TPD_LST (1<<31) - -/* table 4.3 serial eeprom information */ - -#define PROD_ID 0x08 /* char[] */ -#define PROD_ID_LEN 30 -#define HW_REV 0x26 /* char[] */ -#define M_SN 0x3a /* integer */ -#define MEDIA 0x3e /* integer */ -#define HE155MM 0x26 -#define HE622MM 0x27 -#define HE155SM 0x46 -#define HE622SM 0x47 -#define MAC_ADDR 0x42 /* char[] */ - -#define CS_LOW 0x0 -#define CS_HIGH ID_CS /* HOST_CNTL_ID_PROM_SEL */ -#define CLK_LOW 0x0 -#define CLK_HIGH ID_CLOCK /* HOST_CNTL_ID_PROM_CLOCK */ -#define SI_HIGH ID_DIN /* HOST_CNTL_ID_PROM_DATA_IN */ -#define EEPROM_DELAY 400 /* microseconds */ - -#endif /* _HE_H_ */ diff --git a/drivers/atm/idt77105.h b/drivers/atm/idt77105.h deleted file mode 100644 index 8dfea9e361de..000000000000 --- a/drivers/atm/idt77105.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/idt77105.h - IDT77105 (PHY) declarations */ - -/* Written 1999 by Greg Banks, NEC Australia . Based on suni.h */ - - -#ifndef DRIVER_ATM_IDT77105_H -#define DRIVER_ATM_IDT77105_H - -#include -#include - - -/* IDT77105 registers */ - -#define IDT77105_MCR 0x0 /* Master Control Register */ -#define IDT77105_ISTAT 0x1 /* Interrupt Status */ -#define IDT77105_DIAG 0x2 /* Diagnostic Control */ -#define IDT77105_LEDHEC 0x3 /* LED Driver & HEC Status/Control */ -#define IDT77105_CTRLO 0x4 /* Low Byte Counter Register */ -#define IDT77105_CTRHI 0x5 /* High Byte Counter Register */ -#define IDT77105_CTRSEL 0x6 /* Counter Register Read Select */ - -/* IDT77105 register values */ - -/* MCR */ -#define IDT77105_MCR_UPLO 0x80 /* R/W, User Prog'le Output Latch */ -#define IDT77105_MCR_DREC 0x40 /* R/W, Discard Receive Error Cells */ -#define IDT77105_MCR_ECEIO 0x20 /* R/W, Enable Cell Error Interrupts - * Only */ -#define IDT77105_MCR_TDPC 0x10 /* R/W, Transmit Data Parity Check */ -#define IDT77105_MCR_DRIC 0x08 /* R/W, Discard Received Idle Cells */ -#define IDT77105_MCR_HALTTX 0x04 /* R/W, Halt Tx */ -#define IDT77105_MCR_UMODE 0x02 /* R/W, Utopia (cell/byte) Mode */ -#define IDT77105_MCR_EIP 0x01 /* R/W, Enable Interrupt Pin */ - -/* ISTAT */ -#define IDT77105_ISTAT_GOODSIG 0x40 /* R, Good Signal Bit */ -#define IDT77105_ISTAT_HECERR 0x20 /* sticky, HEC Error*/ -#define IDT77105_ISTAT_SCR 0x10 /* sticky, Short Cell Received */ -#define IDT77105_ISTAT_TPE 0x08 /* sticky, Transmit Parity Error */ -#define IDT77105_ISTAT_RSCC 0x04 /* sticky, Rx Signal Condition Change */ -#define IDT77105_ISTAT_RSE 0x02 /* sticky, Rx Symbol Error */ -#define IDT77105_ISTAT_RFO 0x01 /* sticky, Rx FIFO Overrun */ - -/* DIAG */ -#define IDT77105_DIAG_FTD 0x80 /* R/W, Force TxClav deassert */ -#define IDT77105_DIAG_ROS 0x40 /* R/W, RxClav operation select */ -#define IDT77105_DIAG_MPCS 0x20 /* R/W, Multi-PHY config'n select */ -#define IDT77105_DIAG_RFLUSH 0x10 /* R/W, clear receive FIFO */ -#define IDT77105_DIAG_ITPE 0x08 /* R/W, Insert Tx payload error */ -#define IDT77105_DIAG_ITHE 0x04 /* R/W, Insert Tx HEC error */ -#define IDT77105_DIAG_UMODE 0x02 /* R/W, Utopia (cell/byte) Mode */ -#define IDT77105_DIAG_LCMASK 0x03 /* R/W, Loopback Control */ - -#define IDT77105_DIAG_LC_NORMAL 0x00 /* Receive from network */ -#define IDT77105_DIAG_LC_PHY_LOOPBACK 0x02 -#define IDT77105_DIAG_LC_LINE_LOOPBACK 0x03 - -/* LEDHEC */ -#define IDT77105_LEDHEC_DRHC 0x40 /* R/W, Disable Rx HEC check */ -#define IDT77105_LEDHEC_DTHC 0x20 /* R/W, Disable Tx HEC calculation */ -#define IDT77105_LEDHEC_RPWMASK 0x18 /* R/W, RxRef pulse width select */ -#define IDT77105_LEDHEC_TFS 0x04 /* R, Tx FIFO Status (1=empty) */ -#define IDT77105_LEDHEC_TLS 0x02 /* R, Tx LED Status (1=lit) */ -#define IDT77105_LEDHEC_RLS 0x01 /* R, Rx LED Status (1=lit) */ - -#define IDT77105_LEDHEC_RPW_1 0x00 /* RxRef active for 1 RxClk cycle */ -#define IDT77105_LEDHEC_RPW_2 0x08 /* RxRef active for 2 RxClk cycle */ -#define IDT77105_LEDHEC_RPW_4 0x10 /* RxRef active for 4 RxClk cycle */ -#define IDT77105_LEDHEC_RPW_8 0x18 /* RxRef active for 8 RxClk cycle */ - -/* CTRSEL */ -#define IDT77105_CTRSEL_SEC 0x08 /* W, Symbol Error Counter */ -#define IDT77105_CTRSEL_TCC 0x04 /* W, Tx Cell Counter */ -#define IDT77105_CTRSEL_RCC 0x02 /* W, Rx Cell Counter */ -#define IDT77105_CTRSEL_RHEC 0x01 /* W, Rx HEC Error Counter */ - -#ifdef __KERNEL__ -int idt77105_init(struct atm_dev *dev); -#endif - -/* - * Tunable parameters - */ - -/* Time between samples of the hardware cell counters. Should be <= 1 sec */ -#define IDT77105_STATS_TIMER_PERIOD (HZ) -/* Time between checks to see if the signal has been found again */ -#define IDT77105_RESTART_TIMER_PERIOD (5 * HZ) - -#endif diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h deleted file mode 100644 index b059d31364dd..000000000000 --- a/drivers/atm/idt77252.h +++ /dev/null @@ -1,816 +0,0 @@ -/******************************************************************* - * - * Copyright (c) 2000 ATecoM GmbH - * - * The author may be reached at ecd@atecom.com. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - *******************************************************************/ - -#ifndef _IDT77252_H -#define _IDT77252_H 1 - - -#include -#include -#include -#include - -/*****************************************************************************/ -/* */ -/* Makros */ -/* */ -/*****************************************************************************/ -#define VPCI2VC(card, vpi, vci) \ - (((vpi) << card->vcibits) | ((vci) & card->vcimask)) - -/*****************************************************************************/ -/* */ -/* DEBUGGING definitions */ -/* */ -/*****************************************************************************/ - -#define DBG_RAW_CELL 0x00000400 -#define DBG_TINY 0x00000200 -#define DBG_GENERAL 0x00000100 -#define DBG_XGENERAL 0x00000080 -#define DBG_INIT 0x00000040 -#define DBG_DEINIT 0x00000020 -#define DBG_INTERRUPT 0x00000010 -#define DBG_OPEN_CONN 0x00000008 -#define DBG_CLOSE_CONN 0x00000004 -#define DBG_RX_DATA 0x00000002 -#define DBG_TX_DATA 0x00000001 - -#ifdef CONFIG_ATM_IDT77252_DEBUG - -#define CPRINTK(args...) do { if (debug & DBG_CLOSE_CONN) printk(args); } while(0) -#define OPRINTK(args...) do { if (debug & DBG_OPEN_CONN) printk(args); } while(0) -#define IPRINTK(args...) do { if (debug & DBG_INIT) printk(args); } while(0) -#define INTPRINTK(args...) do { if (debug & DBG_INTERRUPT) printk(args); } while(0) -#define DIPRINTK(args...) do { if (debug & DBG_DEINIT) printk(args); } while(0) -#define TXPRINTK(args...) do { if (debug & DBG_TX_DATA) printk(args); } while(0) -#define RXPRINTK(args...) do { if (debug & DBG_RX_DATA) printk(args); } while(0) -#define XPRINTK(args...) do { if (debug & DBG_XGENERAL) printk(args); } while(0) -#define DPRINTK(args...) do { if (debug & DBG_GENERAL) printk(args); } while(0) -#define NPRINTK(args...) do { if (debug & DBG_TINY) printk(args); } while(0) -#define RPRINTK(args...) do { if (debug & DBG_RAW_CELL) printk(args); } while(0) - -#else - -#define CPRINTK(args...) do { } while(0) -#define OPRINTK(args...) do { } while(0) -#define IPRINTK(args...) do { } while(0) -#define INTPRINTK(args...) do { } while(0) -#define DIPRINTK(args...) do { } while(0) -#define TXPRINTK(args...) do { } while(0) -#define RXPRINTK(args...) do { } while(0) -#define XPRINTK(args...) do { } while(0) -#define DPRINTK(args...) do { } while(0) -#define NPRINTK(args...) do { } while(0) -#define RPRINTK(args...) do { } while(0) - -#endif - -#define SCHED_UBR0 0 -#define SCHED_UBR 1 -#define SCHED_VBR 2 -#define SCHED_ABR 3 -#define SCHED_CBR 4 - -#define SCQFULL_TIMEOUT HZ - -/*****************************************************************************/ -/* */ -/* Free Buffer Queue Layout */ -/* */ -/*****************************************************************************/ -#define SAR_FB_SIZE_0 (2048 - 256) -#define SAR_FB_SIZE_1 (4096 - 256) -#define SAR_FB_SIZE_2 (8192 - 256) -#define SAR_FB_SIZE_3 (16384 - 256) - -#define SAR_FBQ0_LOW 4 -#define SAR_FBQ0_HIGH 8 -#define SAR_FBQ1_LOW 2 -#define SAR_FBQ1_HIGH 4 -#define SAR_FBQ2_LOW 1 -#define SAR_FBQ2_HIGH 2 -#define SAR_FBQ3_LOW 1 -#define SAR_FBQ3_HIGH 2 - -#if 0 -#define SAR_TST_RESERVED 44 /* Num TST reserved for UBR/ABR/VBR */ -#else -#define SAR_TST_RESERVED 0 /* Num TST reserved for UBR/ABR/VBR */ -#endif - -#define TCT_CBR 0x00000000 -#define TCT_UBR 0x00000000 -#define TCT_VBR 0x40000000 -#define TCT_ABR 0x80000000 -#define TCT_TYPE 0xc0000000 - -#define TCT_RR 0x20000000 -#define TCT_LMCR 0x08000000 -#define TCT_SCD_MASK 0x0007ffff - -#define TCT_TSIF 0x00004000 -#define TCT_HALT 0x80000000 -#define TCT_IDLE 0x40000000 -#define TCT_FLAG_UBR 0x80000000 - -/*****************************************************************************/ -/* */ -/* Structure describing an IDT77252 */ -/* */ -/*****************************************************************************/ - -struct scqe -{ - u32 word_1; - u32 word_2; - u32 word_3; - u32 word_4; -}; - -#define SCQ_ENTRIES 64 -#define SCQ_SIZE (SCQ_ENTRIES * sizeof(struct scqe)) -#define SCQ_MASK (SCQ_SIZE - 1) - -struct scq_info -{ - struct scqe *base; - struct scqe *next; - struct scqe *last; - dma_addr_t paddr; - spinlock_t lock; - atomic_t used; - unsigned long trans_start; - unsigned long scd; - spinlock_t skblock; - struct sk_buff_head transmit; - struct sk_buff_head pending; -}; - -struct rx_pool { - struct sk_buff_head queue; - unsigned int len; -}; - -struct aal1 { - unsigned int total; - unsigned int count; - struct sk_buff *data; - unsigned char sequence; -}; - -struct vc_map; - -struct rate_estimator { - struct timer_list timer; - unsigned int interval; - unsigned int ewma_log; - u64 cells; - u64 last_cells; - long avcps; - u32 cps; - u32 maxcps; - struct vc_map *vc; -}; - -struct vc_map { - unsigned int index; - unsigned long flags; -#define VCF_TX 0 -#define VCF_RX 1 -#define VCF_IDLE 2 -#define VCF_RSV 3 - unsigned int class; - u8 init_er; - u8 lacr; - u8 max_er; - unsigned int ntste; - spinlock_t lock; - struct atm_vcc *tx_vcc; - struct atm_vcc *rx_vcc; - struct idt77252_dev *card; - struct scq_info *scq; /* To keep track of the SCQ */ - struct rate_estimator *estimator; - int scd_index; - union { - struct rx_pool rx_pool; - struct aal1 aal1; - } rcv; -}; - -/*****************************************************************************/ -/* */ -/* RCTE - Receive Connection Table Entry */ -/* */ -/*****************************************************************************/ - -struct rct_entry -{ - u32 word_1; - u32 buffer_handle; - u32 dma_address; - u32 aal5_crc32; -}; - -/*****************************************************************************/ -/* */ -/* RSQ - Receive Status Queue */ -/* */ -/*****************************************************************************/ - -#define SAR_RSQE_VALID 0x80000000 -#define SAR_RSQE_IDLE 0x40000000 -#define SAR_RSQE_BUF_MASK 0x00030000 -#define SAR_RSQE_BUF_ASGN 0x00008000 -#define SAR_RSQE_NZGFC 0x00004000 -#define SAR_RSQE_EPDU 0x00002000 -#define SAR_RSQE_BUF_CONT 0x00001000 -#define SAR_RSQE_EFCIE 0x00000800 -#define SAR_RSQE_CLP 0x00000400 -#define SAR_RSQE_CRC 0x00000200 -#define SAR_RSQE_CELLCNT 0x000001FF - - -#define RSQSIZE 8192 -#define RSQ_NUM_ENTRIES (RSQSIZE / 16) -#define RSQ_ALIGNMENT 8192 - -struct rsq_entry { - u32 word_1; - u32 word_2; - u32 word_3; - u32 word_4; -}; - -struct rsq_info { - struct rsq_entry *base; - struct rsq_entry *next; - struct rsq_entry *last; - dma_addr_t paddr; -}; - - -/*****************************************************************************/ -/* */ -/* TSQ - Transmit Status Queue */ -/* */ -/*****************************************************************************/ - -#define SAR_TSQE_INVALID 0x80000000 -#define SAR_TSQE_TIMESTAMP 0x00FFFFFF -#define SAR_TSQE_TYPE 0x60000000 -#define SAR_TSQE_TYPE_TIMER 0x00000000 -#define SAR_TSQE_TYPE_TSR 0x20000000 -#define SAR_TSQE_TYPE_IDLE 0x40000000 -#define SAR_TSQE_TYPE_TBD_COMP 0x60000000 - -#define SAR_TSQE_TAG(stat) (((stat) >> 24) & 0x1f) - -#define TSQSIZE 8192 -#define TSQ_NUM_ENTRIES 1024 -#define TSQ_ALIGNMENT 8192 - -struct tsq_entry -{ - u32 word_1; - u32 word_2; -}; - -struct tsq_info -{ - struct tsq_entry *base; - struct tsq_entry *next; - struct tsq_entry *last; - dma_addr_t paddr; -}; - -struct tst_info -{ - struct vc_map *vc; - u32 tste; -}; - -#define TSTE_MASK 0x601fffff - -#define TSTE_OPC_MASK 0x60000000 -#define TSTE_OPC_NULL 0x00000000 -#define TSTE_OPC_CBR 0x20000000 -#define TSTE_OPC_VAR 0x40000000 -#define TSTE_OPC_JMP 0x60000000 - -#define TSTE_PUSH_IDLE 0x01000000 -#define TSTE_PUSH_ACTIVE 0x02000000 - -#define TST_SWITCH_DONE 0 -#define TST_SWITCH_PENDING 1 -#define TST_SWITCH_WAIT 2 - -#define FBQ_SHIFT 9 -#define FBQ_SIZE (1 << FBQ_SHIFT) -#define FBQ_MASK (FBQ_SIZE - 1) - -struct sb_pool -{ - unsigned int index; - struct sk_buff *skb[FBQ_SIZE]; -}; - -#define POOL_HANDLE(queue, index) (((queue + 1) << 16) | (index)) -#define POOL_QUEUE(handle) (((handle) >> 16) - 1) -#define POOL_INDEX(handle) ((handle) & 0xffff) - -struct idt77252_dev -{ - struct tsq_info tsq; /* Transmit Status Queue */ - struct rsq_info rsq; /* Receive Status Queue */ - - struct pci_dev *pcidev; /* PCI handle (desriptor) */ - struct atm_dev *atmdev; /* ATM device desriptor */ - - void __iomem *membase; /* SAR's memory base address */ - unsigned long srambase; /* SAR's sram base address */ - void __iomem *fbq[4]; /* FBQ fill addresses */ - - struct mutex mutex; - spinlock_t cmd_lock; /* for r/w utility/sram */ - - unsigned long softstat; - unsigned long flags; /* see blow */ - - struct work_struct tqueue; - - unsigned long tct_base; /* TCT base address in SRAM */ - unsigned long rct_base; /* RCT base address in SRAM */ - unsigned long rt_base; /* Rate Table base in SRAM */ - unsigned long scd_base; /* SCD base address in SRAM */ - unsigned long tst[2]; /* TST base address in SRAM */ - unsigned long abrst_base; /* ABRST base address in SRAM */ - unsigned long fifo_base; /* RX FIFO base in SRAM */ - - unsigned long irqstat[16]; - - unsigned int sramsize; /* SAR's sram size */ - - unsigned int tct_size; /* total TCT entries */ - unsigned int rct_size; /* total RCT entries */ - unsigned int scd_size; /* length of SCD */ - unsigned int tst_size; /* total TST entries */ - unsigned int tst_free; /* free TSTEs in TST */ - unsigned int abrst_size; /* size of ABRST in words */ - unsigned int fifo_size; /* size of RX FIFO in words */ - - unsigned int vpibits; /* Bits used for VPI index */ - unsigned int vcibits; /* Bits used for VCI index */ - unsigned int vcimask; /* Mask for VCI index */ - - unsigned int utopia_pcr; /* Utopia Itf's Cell Rate */ - unsigned int link_pcr; /* PHY's Peek Cell Rate */ - - struct vc_map **vcs; /* Open Connections */ - struct vc_map **scd2vc; /* SCD to Connection map */ - - struct tst_info *soft_tst; /* TST to Connection map */ - unsigned int tst_index; /* Current TST in use */ - struct timer_list tst_timer; - spinlock_t tst_lock; - unsigned long tst_state; - - struct sb_pool sbpool[4]; /* Pool of RX skbuffs */ - struct sk_buff *raw_cell_head; /* Pointer to raw cell queue */ - u32 *raw_cell_hnd; /* Pointer to RCQ handle */ - dma_addr_t raw_cell_paddr; - - int index; /* SAR's ID */ - int revision; /* chip revision */ - - char name[16]; /* Device name */ - - struct idt77252_dev *next; -}; - - -/* definition for flag field above */ -#define IDT77252_BIT_INIT 1 -#define IDT77252_BIT_INTERRUPT 2 - - -#define ATM_CELL_PAYLOAD 48 - -#define FREEBUF_ALIGNMENT 16 - -/*****************************************************************************/ -/* */ -/* Makros */ -/* */ -/*****************************************************************************/ -#define ALIGN_ADDRESS(addr, alignment) \ - ((((u32)(addr)) + (((u32)(alignment))-1)) & ~(((u32)(alignment)) - 1)) - - -/*****************************************************************************/ -/* */ -/* ABR SAR Network operation Register */ -/* */ -/*****************************************************************************/ - -#define SAR_REG_DR0 (card->membase + 0x00) -#define SAR_REG_DR1 (card->membase + 0x04) -#define SAR_REG_DR2 (card->membase + 0x08) -#define SAR_REG_DR3 (card->membase + 0x0C) -#define SAR_REG_CMD (card->membase + 0x10) -#define SAR_REG_CFG (card->membase + 0x14) -#define SAR_REG_STAT (card->membase + 0x18) -#define SAR_REG_RSQB (card->membase + 0x1C) -#define SAR_REG_RSQT (card->membase + 0x20) -#define SAR_REG_RSQH (card->membase + 0x24) -#define SAR_REG_CDC (card->membase + 0x28) -#define SAR_REG_VPEC (card->membase + 0x2C) -#define SAR_REG_ICC (card->membase + 0x30) -#define SAR_REG_RAWCT (card->membase + 0x34) -#define SAR_REG_TMR (card->membase + 0x38) -#define SAR_REG_TSTB (card->membase + 0x3C) -#define SAR_REG_TSQB (card->membase + 0x40) -#define SAR_REG_TSQT (card->membase + 0x44) -#define SAR_REG_TSQH (card->membase + 0x48) -#define SAR_REG_GP (card->membase + 0x4C) -#define SAR_REG_VPM (card->membase + 0x50) -#define SAR_REG_RXFD (card->membase + 0x54) -#define SAR_REG_RXFT (card->membase + 0x58) -#define SAR_REG_RXFH (card->membase + 0x5C) -#define SAR_REG_RAWHND (card->membase + 0x60) -#define SAR_REG_RXSTAT (card->membase + 0x64) -#define SAR_REG_ABRSTD (card->membase + 0x68) -#define SAR_REG_ABRRQ (card->membase + 0x6C) -#define SAR_REG_VBRRQ (card->membase + 0x70) -#define SAR_REG_RTBL (card->membase + 0x74) -#define SAR_REG_MDFCT (card->membase + 0x78) -#define SAR_REG_TXSTAT (card->membase + 0x7C) -#define SAR_REG_TCMDQ (card->membase + 0x80) -#define SAR_REG_IRCP (card->membase + 0x84) -#define SAR_REG_FBQP0 (card->membase + 0x88) -#define SAR_REG_FBQP1 (card->membase + 0x8C) -#define SAR_REG_FBQP2 (card->membase + 0x90) -#define SAR_REG_FBQP3 (card->membase + 0x94) -#define SAR_REG_FBQS0 (card->membase + 0x98) -#define SAR_REG_FBQS1 (card->membase + 0x9C) -#define SAR_REG_FBQS2 (card->membase + 0xA0) -#define SAR_REG_FBQS3 (card->membase + 0xA4) -#define SAR_REG_FBQWP0 (card->membase + 0xA8) -#define SAR_REG_FBQWP1 (card->membase + 0xAC) -#define SAR_REG_FBQWP2 (card->membase + 0xB0) -#define SAR_REG_FBQWP3 (card->membase + 0xB4) -#define SAR_REG_NOW (card->membase + 0xB8) - - -/*****************************************************************************/ -/* */ -/* Commands */ -/* */ -/*****************************************************************************/ - -#define SAR_CMD_NO_OPERATION 0x00000000 -#define SAR_CMD_OPENCLOSE_CONNECTION 0x20000000 -#define SAR_CMD_WRITE_SRAM 0x40000000 -#define SAR_CMD_READ_SRAM 0x50000000 -#define SAR_CMD_READ_UTILITY 0x80000000 -#define SAR_CMD_WRITE_UTILITY 0x90000000 - -#define SAR_CMD_OPEN_CONNECTION (SAR_CMD_OPENCLOSE_CONNECTION | 0x00080000) -#define SAR_CMD_CLOSE_CONNECTION SAR_CMD_OPENCLOSE_CONNECTION - - -/*****************************************************************************/ -/* */ -/* Configuration Register bits */ -/* */ -/*****************************************************************************/ - -#define SAR_CFG_SWRST 0x80000000 /* Software reset */ -#define SAR_CFG_LOOP 0x40000000 /* Internal Loopback */ -#define SAR_CFG_RXPTH 0x20000000 /* Receive Path Enable */ -#define SAR_CFG_IDLE_CLP 0x10000000 /* SAR set CLP Bits of Null Cells */ -#define SAR_CFG_TX_FIFO_SIZE_1 0x04000000 /* TX FIFO Size = 1 cell */ -#define SAR_CFG_TX_FIFO_SIZE_2 0x08000000 /* TX FIFO Size = 2 cells */ -#define SAR_CFG_TX_FIFO_SIZE_4 0x0C000000 /* TX FIFO Size = 4 cells */ -#define SAR_CFG_TX_FIFO_SIZE_9 0x00000000 /* TX FIFO Size = 9 cells (full) */ -#define SAR_CFG_NO_IDLE 0x02000000 /* SAR sends no Null Cells */ -#define SAR_CFG_RSVD1 0x01000000 /* Reserved */ -#define SAR_CFG_RXSTQ_SIZE_2k 0x00000000 /* RX Stat Queue Size = 2048 byte */ -#define SAR_CFG_RXSTQ_SIZE_4k 0x00400000 /* RX Stat Queue Size = 4096 byte */ -#define SAR_CFG_RXSTQ_SIZE_8k 0x00800000 /* RX Stat Queue Size = 8192 byte */ -#define SAR_CFG_RXSTQ_SIZE_R 0x00C00000 /* RX Stat Queue Size = reserved */ -#define SAR_CFG_ICAPT 0x00200000 /* accept Invalid Cells */ -#define SAR_CFG_IGGFC 0x00100000 /* Ignore GFC */ -#define SAR_CFG_VPVCS_0 0x00000000 /* VPI/VCI Select bit range */ -#define SAR_CFG_VPVCS_1 0x00040000 /* VPI/VCI Select bit range */ -#define SAR_CFG_VPVCS_2 0x00080000 /* VPI/VCI Select bit range */ -#define SAR_CFG_VPVCS_8 0x000C0000 /* VPI/VCI Select bit range */ -#define SAR_CFG_CNTBL_1k 0x00000000 /* Connection Table Size */ -#define SAR_CFG_CNTBL_4k 0x00010000 /* Connection Table Size */ -#define SAR_CFG_CNTBL_16k 0x00020000 /* Connection Table Size */ -#define SAR_CFG_CNTBL_512 0x00030000 /* Connection Table Size */ -#define SAR_CFG_VPECA 0x00008000 /* VPI/VCI Error Cell Accept */ -#define SAR_CFG_RXINT_NOINT 0x00000000 /* No Interrupt on PDU received */ -#define SAR_CFG_RXINT_NODELAY 0x00001000 /* Interrupt without delay to host*/ -#define SAR_CFG_RXINT_256US 0x00002000 /* Interrupt with delay 256 usec */ -#define SAR_CFG_RXINT_505US 0x00003000 /* Interrupt with delay 505 usec */ -#define SAR_CFG_RXINT_742US 0x00004000 /* Interrupt with delay 742 usec */ -#define SAR_CFG_RAWIE 0x00000800 /* Raw Cell Queue Interrupt Enable*/ -#define SAR_CFG_RQFIE 0x00000400 /* RSQ Almost Full Int Enable */ -#define SAR_CFG_RSVD2 0x00000200 /* Reserved */ -#define SAR_CFG_CACHE 0x00000100 /* DMA on Cache Line Boundary */ -#define SAR_CFG_TMOIE 0x00000080 /* Timer Roll Over Int Enable */ -#define SAR_CFG_FBIE 0x00000040 /* Free Buffer Queue Int Enable */ -#define SAR_CFG_TXEN 0x00000020 /* Transmit Operation Enable */ -#define SAR_CFG_TXINT 0x00000010 /* Transmit status Int Enable */ -#define SAR_CFG_TXUIE 0x00000008 /* Transmit underrun Int Enable */ -#define SAR_CFG_UMODE 0x00000004 /* Utopia Mode Select */ -#define SAR_CFG_TXSFI 0x00000002 /* Transmit status Full Int Enable*/ -#define SAR_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */ - -#define SAR_CFG_TX_FIFO_SIZE_MASK 0x0C000000 /* TX FIFO Size Mask */ -#define SAR_CFG_RXSTQSIZE_MASK 0x00C00000 -#define SAR_CFG_CNTBL_MASK 0x00030000 -#define SAR_CFG_RXINT_MASK 0x00007000 - - -/*****************************************************************************/ -/* */ -/* Status Register bits */ -/* */ -/*****************************************************************************/ - -#define SAR_STAT_FRAC_3 0xF0000000 /* Fraction of Free Buffer Queue 3 */ -#define SAR_STAT_FRAC_2 0x0F000000 /* Fraction of Free Buffer Queue 2 */ -#define SAR_STAT_FRAC_1 0x00F00000 /* Fraction of Free Buffer Queue 1 */ -#define SAR_STAT_FRAC_0 0x000F0000 /* Fraction of Free Buffer Queue 0 */ -#define SAR_STAT_TSIF 0x00008000 /* Transmit Status Indicator */ -#define SAR_STAT_TXICP 0x00004000 /* Transmit Status Indicator */ -#define SAR_STAT_RSVD1 0x00002000 /* Reserved */ -#define SAR_STAT_TSQF 0x00001000 /* Transmit Status Queue full */ -#define SAR_STAT_TMROF 0x00000800 /* Timer overflow */ -#define SAR_STAT_PHYI 0x00000400 /* PHY device Interrupt flag */ -#define SAR_STAT_CMDBZ 0x00000200 /* ABR SAR Command Busy Flag */ -#define SAR_STAT_FBQ3A 0x00000100 /* Free Buffer Queue 3 Attention */ -#define SAR_STAT_FBQ2A 0x00000080 /* Free Buffer Queue 2 Attention */ -#define SAR_STAT_RSQF 0x00000040 /* Receive Status Queue full */ -#define SAR_STAT_EPDU 0x00000020 /* End Of PDU Flag */ -#define SAR_STAT_RAWCF 0x00000010 /* Raw Cell Flag */ -#define SAR_STAT_FBQ1A 0x00000008 /* Free Buffer Queue 1 Attention */ -#define SAR_STAT_FBQ0A 0x00000004 /* Free Buffer Queue 0 Attention */ -#define SAR_STAT_RSQAF 0x00000002 /* Receive Status Queue almost full*/ -#define SAR_STAT_RSVD2 0x00000001 /* Reserved */ - - -/*****************************************************************************/ -/* */ -/* General Purpose Register bits */ -/* */ -/*****************************************************************************/ - -#define SAR_GP_TXNCC_MASK 0xff000000 /* Transmit Negative Credit Count */ -#define SAR_GP_EEDI 0x00010000 /* EEPROM Data In */ -#define SAR_GP_BIGE 0x00008000 /* Big Endian Operation */ -#define SAR_GP_RM_NORMAL 0x00000000 /* Normal handling of RM cells */ -#define SAR_GP_RM_TO_RCQ 0x00002000 /* put RM cells into Raw Cell Queue */ -#define SAR_GP_RM_RSVD 0x00004000 /* Reserved */ -#define SAR_GP_RM_INHIBIT 0x00006000 /* Inhibit update of Connection tab */ -#define SAR_GP_PHY_RESET 0x00000008 /* PHY Reset */ -#define SAR_GP_EESCLK 0x00000004 /* EEPROM SCLK */ -#define SAR_GP_EECS 0x00000002 /* EEPROM Chip Select */ -#define SAR_GP_EEDO 0x00000001 /* EEPROM Data Out */ - - -/*****************************************************************************/ -/* */ -/* SAR local SRAM layout for 128k work SRAM */ -/* */ -/*****************************************************************************/ - -#define SAR_SRAM_SCD_SIZE 12 -#define SAR_SRAM_TCT_SIZE 8 -#define SAR_SRAM_RCT_SIZE 4 - -#define SAR_SRAM_TCT_128_BASE 0x00000 -#define SAR_SRAM_TCT_128_TOP 0x01fff -#define SAR_SRAM_RCT_128_BASE 0x02000 -#define SAR_SRAM_RCT_128_TOP 0x02fff -#define SAR_SRAM_FB0_128_BASE 0x03000 -#define SAR_SRAM_FB0_128_TOP 0x033ff -#define SAR_SRAM_FB1_128_BASE 0x03400 -#define SAR_SRAM_FB1_128_TOP 0x037ff -#define SAR_SRAM_FB2_128_BASE 0x03800 -#define SAR_SRAM_FB2_128_TOP 0x03bff -#define SAR_SRAM_FB3_128_BASE 0x03c00 -#define SAR_SRAM_FB3_128_TOP 0x03fff -#define SAR_SRAM_SCD_128_BASE 0x04000 -#define SAR_SRAM_SCD_128_TOP 0x07fff -#define SAR_SRAM_TST1_128_BASE 0x08000 -#define SAR_SRAM_TST1_128_TOP 0x0bfff -#define SAR_SRAM_TST2_128_BASE 0x0c000 -#define SAR_SRAM_TST2_128_TOP 0x0ffff -#define SAR_SRAM_ABRSTD_128_BASE 0x10000 -#define SAR_SRAM_ABRSTD_128_TOP 0x13fff -#define SAR_SRAM_RT_128_BASE 0x14000 -#define SAR_SRAM_RT_128_TOP 0x15fff - -#define SAR_SRAM_FIFO_128_BASE 0x18000 -#define SAR_SRAM_FIFO_128_TOP 0x1ffff - - -/*****************************************************************************/ -/* */ -/* SAR local SRAM layout for 32k work SRAM */ -/* */ -/*****************************************************************************/ - -#define SAR_SRAM_TCT_32_BASE 0x00000 -#define SAR_SRAM_TCT_32_TOP 0x00fff -#define SAR_SRAM_RCT_32_BASE 0x01000 -#define SAR_SRAM_RCT_32_TOP 0x017ff -#define SAR_SRAM_FB0_32_BASE 0x01800 -#define SAR_SRAM_FB0_32_TOP 0x01bff -#define SAR_SRAM_FB1_32_BASE 0x01c00 -#define SAR_SRAM_FB1_32_TOP 0x01fff -#define SAR_SRAM_FB2_32_BASE 0x02000 -#define SAR_SRAM_FB2_32_TOP 0x023ff -#define SAR_SRAM_FB3_32_BASE 0x02400 -#define SAR_SRAM_FB3_32_TOP 0x027ff -#define SAR_SRAM_SCD_32_BASE 0x02800 -#define SAR_SRAM_SCD_32_TOP 0x03fff -#define SAR_SRAM_TST1_32_BASE 0x04000 -#define SAR_SRAM_TST1_32_TOP 0x04fff -#define SAR_SRAM_TST2_32_BASE 0x05000 -#define SAR_SRAM_TST2_32_TOP 0x05fff -#define SAR_SRAM_ABRSTD_32_BASE 0x06000 -#define SAR_SRAM_ABRSTD_32_TOP 0x067ff -#define SAR_SRAM_RT_32_BASE 0x06800 -#define SAR_SRAM_RT_32_TOP 0x06fff -#define SAR_SRAM_FIFO_32_BASE 0x07000 -#define SAR_SRAM_FIFO_32_TOP 0x07fff - - -/*****************************************************************************/ -/* */ -/* TSR - Transmit Status Request */ -/* */ -/*****************************************************************************/ - -#define SAR_TSR_TYPE_TSR 0x80000000 -#define SAR_TSR_TYPE_TBD 0x00000000 -#define SAR_TSR_TSIF 0x20000000 -#define SAR_TSR_TAG_MASK 0x01F00000 - - -/*****************************************************************************/ -/* */ -/* TBD - Transmit Buffer Descriptor */ -/* */ -/*****************************************************************************/ - -#define SAR_TBD_EPDU 0x40000000 -#define SAR_TBD_TSIF 0x20000000 -#define SAR_TBD_OAM 0x10000000 -#define SAR_TBD_AAL0 0x00000000 -#define SAR_TBD_AAL34 0x04000000 -#define SAR_TBD_AAL5 0x08000000 -#define SAR_TBD_GTSI 0x02000000 -#define SAR_TBD_TAG_MASK 0x01F00000 - -#define SAR_TBD_VPI_MASK 0x0FF00000 -#define SAR_TBD_VCI_MASK 0x000FFFF0 -#define SAR_TBD_VC_MASK (SAR_TBD_VPI_MASK | SAR_TBD_VCI_MASK) - -#define SAR_TBD_VPI_SHIFT 20 -#define SAR_TBD_VCI_SHIFT 4 - - -/*****************************************************************************/ -/* */ -/* RXFD - Receive FIFO Descriptor */ -/* */ -/*****************************************************************************/ - -#define SAR_RXFD_SIZE_MASK 0x0F000000 -#define SAR_RXFD_SIZE_512 0x00000000 /* 512 words */ -#define SAR_RXFD_SIZE_1K 0x01000000 /* 1k words */ -#define SAR_RXFD_SIZE_2K 0x02000000 /* 2k words */ -#define SAR_RXFD_SIZE_4K 0x03000000 /* 4k words */ -#define SAR_RXFD_SIZE_8K 0x04000000 /* 8k words */ -#define SAR_RXFD_SIZE_16K 0x05000000 /* 16k words */ -#define SAR_RXFD_SIZE_32K 0x06000000 /* 32k words */ -#define SAR_RXFD_SIZE_64K 0x07000000 /* 64k words */ -#define SAR_RXFD_SIZE_128K 0x08000000 /* 128k words */ -#define SAR_RXFD_SIZE_256K 0x09000000 /* 256k words */ -#define SAR_RXFD_ADDR_MASK 0x001ffc00 - - -/*****************************************************************************/ -/* */ -/* ABRSTD - ABR + VBR Schedule Tables */ -/* */ -/*****************************************************************************/ - -#define SAR_ABRSTD_SIZE_MASK 0x07000000 -#define SAR_ABRSTD_SIZE_512 0x00000000 /* 512 words */ -#define SAR_ABRSTD_SIZE_1K 0x01000000 /* 1k words */ -#define SAR_ABRSTD_SIZE_2K 0x02000000 /* 2k words */ -#define SAR_ABRSTD_SIZE_4K 0x03000000 /* 4k words */ -#define SAR_ABRSTD_SIZE_8K 0x04000000 /* 8k words */ -#define SAR_ABRSTD_SIZE_16K 0x05000000 /* 16k words */ -#define SAR_ABRSTD_ADDR_MASK 0x001ffc00 - - -/*****************************************************************************/ -/* */ -/* RCTE - Receive Connection Table Entry */ -/* */ -/*****************************************************************************/ - -#define SAR_RCTE_IL_MASK 0xE0000000 /* inactivity limit */ -#define SAR_RCTE_IC_MASK 0x1C000000 /* inactivity count */ -#define SAR_RCTE_RSVD 0x02000000 /* reserved */ -#define SAR_RCTE_LCD 0x01000000 /* last cell data */ -#define SAR_RCTE_CI_VC 0x00800000 /* EFCI in previous cell of VC */ -#define SAR_RCTE_FBP_01 0x00000000 /* 1. cell->FBQ0, others->FBQ1 */ -#define SAR_RCTE_FBP_1 0x00200000 /* use FBQ 1 for all cells */ -#define SAR_RCTE_FBP_2 0x00400000 /* use FBQ 2 for all cells */ -#define SAR_RCTE_FBP_3 0x00600000 /* use FBQ 3 for all cells */ -#define SAR_RCTE_NZ_GFC 0x00100000 /* non zero GFC in all cell of VC */ -#define SAR_RCTE_CONNECTOPEN 0x00080000 /* VC is open */ -#define SAR_RCTE_AAL_MASK 0x00070000 /* mask for AAL type field s.b. */ -#define SAR_RCTE_RAWCELLINTEN 0x00008000 /* raw cell interrupt enable */ -#define SAR_RCTE_RXCONCELLADDR 0x00004000 /* RX constant cell address */ -#define SAR_RCTE_BUFFSTAT_MASK 0x00003000 /* buffer status */ -#define SAR_RCTE_EFCI 0x00000800 /* EFCI Congestion flag */ -#define SAR_RCTE_CLP 0x00000400 /* Cell Loss Priority flag */ -#define SAR_RCTE_CRC 0x00000200 /* Received CRC Error */ -#define SAR_RCTE_CELLCNT_MASK 0x000001FF /* cell Count */ - -#define SAR_RCTE_AAL0 0x00000000 /* AAL types for ALL field */ -#define SAR_RCTE_AAL34 0x00010000 -#define SAR_RCTE_AAL5 0x00020000 -#define SAR_RCTE_RCQ 0x00030000 -#define SAR_RCTE_OAM 0x00040000 - -#define TCMDQ_START 0x01000000 -#define TCMDQ_LACR 0x02000000 -#define TCMDQ_START_LACR 0x03000000 -#define TCMDQ_INIT_ER 0x04000000 -#define TCMDQ_HALT 0x05000000 - - -struct idt77252_skb_prv { - struct scqe tbd; /* Transmit Buffer Descriptor */ - dma_addr_t paddr; /* DMA handle */ - u32 pool; /* sb_pool handle */ -} __packed; - -#define IDT77252_PRV_TBD(skb) \ - (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->tbd) -#define IDT77252_PRV_PADDR(skb) \ - (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->paddr) -#define IDT77252_PRV_POOL(skb) \ - (((struct idt77252_skb_prv *)(ATM_SKB(skb)+1))->pool) - -/*****************************************************************************/ -/* */ -/* PCI related items */ -/* */ -/*****************************************************************************/ - -#ifndef PCI_VENDOR_ID_IDT -#define PCI_VENDOR_ID_IDT 0x111D -#endif /* PCI_VENDOR_ID_IDT */ - -#ifndef PCI_DEVICE_ID_IDT_IDT77252 -#define PCI_DEVICE_ID_IDT_IDT77252 0x0003 -#endif /* PCI_DEVICE_ID_IDT_IDT772052 */ - - -#endif /* !(_IDT77252_H) */ diff --git a/drivers/atm/idt77252_tables.h b/drivers/atm/idt77252_tables.h deleted file mode 100644 index 12b81e046a7b..000000000000 --- a/drivers/atm/idt77252_tables.h +++ /dev/null @@ -1,781 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Do not edit, automatically generated by `./genrtbl'. - * - * Cell Line Rate: 353207.55 (155520000 bps) - */ - -static unsigned int log_to_rate[] = -{ -/* 000 */ 0x8d022e27, /* cps = 10.02, nrm = 3, interval = 35264.00 */ -/* 001 */ 0x8d362e11, /* cps = 10.42, nrm = 3, interval = 33856.00 */ -/* 002 */ 0x8d6e2bf8, /* cps = 10.86, nrm = 3, interval = 32512.00 */ -/* 003 */ 0x8da82bcf, /* cps = 11.31, nrm = 3, interval = 31200.00 */ -/* 004 */ 0x8de42ba8, /* cps = 11.78, nrm = 3, interval = 29952.00 */ -/* 005 */ 0x8e242b82, /* cps = 12.28, nrm = 3, interval = 28736.00 */ -/* 006 */ 0x8e662b5e, /* cps = 12.80, nrm = 3, interval = 27584.00 */ -/* 007 */ 0x8eaa2b3c, /* cps = 13.33, nrm = 3, interval = 26496.00 */ -/* 008 */ 0x8ef22b1a, /* cps = 13.89, nrm = 3, interval = 25408.00 */ -/* 009 */ 0x8f3e2afa, /* cps = 14.48, nrm = 3, interval = 24384.00 */ -/* 010 */ 0x8f8a2adc, /* cps = 15.08, nrm = 3, interval = 23424.00 */ -/* 011 */ 0x8fdc2abe, /* cps = 15.72, nrm = 3, interval = 22464.00 */ -/* 012 */ 0x90182aa2, /* cps = 16.38, nrm = 3, interval = 21568.00 */ -/* 013 */ 0x90422a87, /* cps = 17.03, nrm = 3, interval = 20704.00 */ -/* 014 */ 0x90702a6d, /* cps = 17.75, nrm = 3, interval = 19872.00 */ -/* 015 */ 0x90a02a54, /* cps = 18.50, nrm = 3, interval = 19072.00 */ -/* 016 */ 0x90d22a3c, /* cps = 19.28, nrm = 3, interval = 18304.00 */ -/* 017 */ 0x91062a25, /* cps = 20.09, nrm = 3, interval = 17568.00 */ -/* 018 */ 0x913c2a0f, /* cps = 20.94, nrm = 3, interval = 16864.00 */ -/* 019 */ 0x917427f3, /* cps = 21.81, nrm = 3, interval = 16176.00 */ -/* 020 */ 0x91b027ca, /* cps = 22.75, nrm = 3, interval = 15520.00 */ -/* 021 */ 0x91ec27a3, /* cps = 23.69, nrm = 3, interval = 14896.00 */ -/* 022 */ 0x922c277e, /* cps = 24.69, nrm = 3, interval = 14304.00 */ -/* 023 */ 0x926e275a, /* cps = 25.72, nrm = 3, interval = 13728.00 */ -/* 024 */ 0x92b42737, /* cps = 26.81, nrm = 3, interval = 13168.00 */ -/* 025 */ 0x92fc2716, /* cps = 27.94, nrm = 3, interval = 12640.00 */ -/* 026 */ 0x934626f6, /* cps = 29.09, nrm = 3, interval = 12128.00 */ -/* 027 */ 0x939426d8, /* cps = 30.31, nrm = 3, interval = 11648.00 */ -/* 028 */ 0x93e426bb, /* cps = 31.56, nrm = 3, interval = 11184.00 */ -/* 029 */ 0x941e269e, /* cps = 32.94, nrm = 3, interval = 10720.00 */ -/* 030 */ 0x944a2683, /* cps = 34.31, nrm = 3, interval = 10288.00 */ -/* 031 */ 0x9476266a, /* cps = 35.69, nrm = 3, interval = 9888.00 */ -/* 032 */ 0x94a62651, /* cps = 37.19, nrm = 3, interval = 9488.00 */ -/* 033 */ 0x94d82639, /* cps = 38.75, nrm = 3, interval = 9104.00 */ -/* 034 */ 0x950c6622, /* cps = 40.38, nrm = 4, interval = 8736.00 */ -/* 035 */ 0x9544660c, /* cps = 42.12, nrm = 4, interval = 8384.00 */ -/* 036 */ 0x957c63ee, /* cps = 43.88, nrm = 4, interval = 8048.00 */ -/* 037 */ 0x95b663c6, /* cps = 45.69, nrm = 4, interval = 7728.00 */ -/* 038 */ 0x95f4639f, /* cps = 47.62, nrm = 4, interval = 7416.00 */ -/* 039 */ 0x96346379, /* cps = 49.62, nrm = 4, interval = 7112.00 */ -/* 040 */ 0x96766356, /* cps = 51.69, nrm = 4, interval = 6832.00 */ -/* 041 */ 0x96bc6333, /* cps = 53.88, nrm = 4, interval = 6552.00 */ -/* 042 */ 0x97046312, /* cps = 56.12, nrm = 4, interval = 6288.00 */ -/* 043 */ 0x974e62f3, /* cps = 58.44, nrm = 4, interval = 6040.00 */ -/* 044 */ 0x979e62d4, /* cps = 60.94, nrm = 4, interval = 5792.00 */ -/* 045 */ 0x97f062b7, /* cps = 63.50, nrm = 4, interval = 5560.00 */ -/* 046 */ 0x9822629b, /* cps = 66.12, nrm = 4, interval = 5336.00 */ -/* 047 */ 0x984e6280, /* cps = 68.88, nrm = 4, interval = 5120.00 */ -/* 048 */ 0x987e6266, /* cps = 71.88, nrm = 4, interval = 4912.00 */ -/* 049 */ 0x98ac624e, /* cps = 74.75, nrm = 4, interval = 4720.00 */ -/* 050 */ 0x98e06236, /* cps = 78.00, nrm = 4, interval = 4528.00 */ -/* 051 */ 0x9914a21f, /* cps = 81.25, nrm = 8, interval = 4344.00 */ -/* 052 */ 0x994aa209, /* cps = 84.62, nrm = 8, interval = 4168.00 */ -/* 053 */ 0x99829fe9, /* cps = 88.12, nrm = 8, interval = 4004.00 */ -/* 054 */ 0x99be9fc1, /* cps = 91.88, nrm = 8, interval = 3844.00 */ -/* 055 */ 0x99fc9f9a, /* cps = 95.75, nrm = 8, interval = 3688.00 */ -/* 056 */ 0x9a3c9f75, /* cps = 99.75, nrm = 8, interval = 3540.00 */ -/* 057 */ 0x9a809f51, /* cps = 104.00, nrm = 8, interval = 3396.00 */ -/* 058 */ 0x9ac49f2f, /* cps = 108.25, nrm = 8, interval = 3260.00 */ -/* 059 */ 0x9b0e9f0e, /* cps = 112.88, nrm = 8, interval = 3128.00 */ -/* 060 */ 0x9b589eef, /* cps = 117.50, nrm = 8, interval = 3004.00 */ -/* 061 */ 0x9ba69ed1, /* cps = 122.38, nrm = 8, interval = 2884.00 */ -/* 062 */ 0x9bf89eb4, /* cps = 127.50, nrm = 8, interval = 2768.00 */ -/* 063 */ 0x9c269e98, /* cps = 132.75, nrm = 8, interval = 2656.00 */ -/* 064 */ 0x9c549e7d, /* cps = 138.50, nrm = 8, interval = 2548.00 */ -/* 065 */ 0x9c849e63, /* cps = 144.50, nrm = 8, interval = 2444.00 */ -/* 066 */ 0x9cb29e4b, /* cps = 150.25, nrm = 8, interval = 2348.00 */ -/* 067 */ 0x9ce69e33, /* cps = 156.75, nrm = 8, interval = 2252.00 */ -/* 068 */ 0x9d1cde1c, /* cps = 163.50, nrm = 16, interval = 2160.00 */ -/* 069 */ 0x9d50de07, /* cps = 170.00, nrm = 16, interval = 2076.00 */ -/* 070 */ 0x9d8adbe4, /* cps = 177.25, nrm = 16, interval = 1992.00 */ -/* 071 */ 0x9dc4dbbc, /* cps = 184.50, nrm = 16, interval = 1912.00 */ -/* 072 */ 0x9e02db96, /* cps = 192.25, nrm = 16, interval = 1836.00 */ -/* 073 */ 0x9e42db71, /* cps = 200.25, nrm = 16, interval = 1762.00 */ -/* 074 */ 0x9e86db4d, /* cps = 208.75, nrm = 16, interval = 1690.00 */ -/* 075 */ 0x9ecedb2b, /* cps = 217.75, nrm = 16, interval = 1622.00 */ -/* 076 */ 0x9f16db0a, /* cps = 226.75, nrm = 16, interval = 1556.00 */ -/* 077 */ 0x9f62daeb, /* cps = 236.25, nrm = 16, interval = 1494.00 */ -/* 078 */ 0x9fb2dacd, /* cps = 246.25, nrm = 16, interval = 1434.00 */ -/* 079 */ 0xa002dab0, /* cps = 256.50, nrm = 16, interval = 1376.00 */ -/* 080 */ 0xa02eda94, /* cps = 267.50, nrm = 16, interval = 1320.00 */ -/* 081 */ 0xa05ada7a, /* cps = 278.50, nrm = 16, interval = 1268.00 */ -/* 082 */ 0xa088da60, /* cps = 290.00, nrm = 16, interval = 1216.00 */ -/* 083 */ 0xa0b8da48, /* cps = 302.00, nrm = 16, interval = 1168.00 */ -/* 084 */ 0xa0ecda30, /* cps = 315.00, nrm = 16, interval = 1120.00 */ -/* 085 */ 0xa1211a1a, /* cps = 328.00, nrm = 32, interval = 1076.00 */ -/* 086 */ 0xa1591a04, /* cps = 342.00, nrm = 32, interval = 1032.00 */ -/* 087 */ 0xa19117df, /* cps = 356.00, nrm = 32, interval = 991.00 */ -/* 088 */ 0xa1cd17b7, /* cps = 371.00, nrm = 32, interval = 951.00 */ -/* 089 */ 0xa20b1791, /* cps = 386.50, nrm = 32, interval = 913.00 */ -/* 090 */ 0xa24d176c, /* cps = 403.00, nrm = 32, interval = 876.00 */ -/* 091 */ 0xa28f1749, /* cps = 419.50, nrm = 32, interval = 841.00 */ -/* 092 */ 0xa2d71727, /* cps = 437.50, nrm = 32, interval = 807.00 */ -/* 093 */ 0xa31f1707, /* cps = 455.50, nrm = 32, interval = 775.00 */ -/* 094 */ 0xa36d16e7, /* cps = 475.00, nrm = 32, interval = 743.00 */ -/* 095 */ 0xa3bd16c9, /* cps = 495.00, nrm = 32, interval = 713.00 */ -/* 096 */ 0xa40716ad, /* cps = 515.00, nrm = 32, interval = 685.00 */ -/* 097 */ 0xa4331691, /* cps = 537.00, nrm = 32, interval = 657.00 */ -/* 098 */ 0xa45f1677, /* cps = 559.00, nrm = 32, interval = 631.00 */ -/* 099 */ 0xa48f165d, /* cps = 583.00, nrm = 32, interval = 605.00 */ -/* 100 */ 0xa4bf1645, /* cps = 607.00, nrm = 32, interval = 581.00 */ -/* 101 */ 0xa4f1162e, /* cps = 632.00, nrm = 32, interval = 558.00 */ -/* 102 */ 0xa5291617, /* cps = 660.00, nrm = 32, interval = 535.00 */ -/* 103 */ 0xa55f1602, /* cps = 687.00, nrm = 32, interval = 514.00 */ -/* 104 */ 0xa59913da, /* cps = 716.00, nrm = 32, interval = 493.00 */ -/* 105 */ 0xa5d513b2, /* cps = 746.00, nrm = 32, interval = 473.00 */ -/* 106 */ 0xa613138c, /* cps = 777.00, nrm = 32, interval = 454.00 */ -/* 107 */ 0xa6551368, /* cps = 810.00, nrm = 32, interval = 436.00 */ -/* 108 */ 0xa6971345, /* cps = 843.00, nrm = 32, interval = 418.50 */ -/* 109 */ 0xa6df1323, /* cps = 879.00, nrm = 32, interval = 401.50 */ -/* 110 */ 0xa7291303, /* cps = 916.00, nrm = 32, interval = 385.50 */ -/* 111 */ 0xa77512e4, /* cps = 954.00, nrm = 32, interval = 370.00 */ -/* 112 */ 0xa7c512c6, /* cps = 994.00, nrm = 32, interval = 355.00 */ -/* 113 */ 0xa80d12a9, /* cps = 1036.00, nrm = 32, interval = 340.50 */ -/* 114 */ 0xa839128e, /* cps = 1080.00, nrm = 32, interval = 327.00 */ -/* 115 */ 0xa8651274, /* cps = 1124.00, nrm = 32, interval = 314.00 */ -/* 116 */ 0xa895125a, /* cps = 1172.00, nrm = 32, interval = 301.00 */ -/* 117 */ 0xa8c71242, /* cps = 1222.00, nrm = 32, interval = 289.00 */ -/* 118 */ 0xa8f9122b, /* cps = 1272.00, nrm = 32, interval = 277.50 */ -/* 119 */ 0xa92f1214, /* cps = 1326.00, nrm = 32, interval = 266.00 */ -/* 120 */ 0xa9670ffe, /* cps = 1382.00, nrm = 32, interval = 255.50 */ -/* 121 */ 0xa9a10fd5, /* cps = 1440.00, nrm = 32, interval = 245.25 */ -/* 122 */ 0xa9db0fae, /* cps = 1498.00, nrm = 32, interval = 235.50 */ -/* 123 */ 0xaa1b0f88, /* cps = 1562.00, nrm = 32, interval = 226.00 */ -/* 124 */ 0xaa5d0f63, /* cps = 1628.00, nrm = 32, interval = 216.75 */ -/* 125 */ 0xaaa10f41, /* cps = 1696.00, nrm = 32, interval = 208.25 */ -/* 126 */ 0xaae90f1f, /* cps = 1768.00, nrm = 32, interval = 199.75 */ -/* 127 */ 0xab330eff, /* cps = 1842.00, nrm = 32, interval = 191.75 */ -/* 128 */ 0xab7f0ee0, /* cps = 1918.00, nrm = 32, interval = 184.00 */ -/* 129 */ 0xabd10ec2, /* cps = 2000.00, nrm = 32, interval = 176.50 */ -/* 130 */ 0xac110ea6, /* cps = 2080.00, nrm = 32, interval = 169.50 */ -/* 131 */ 0xac3d0e8b, /* cps = 2168.00, nrm = 32, interval = 162.75 */ -/* 132 */ 0xac6d0e70, /* cps = 2264.00, nrm = 32, interval = 156.00 */ -/* 133 */ 0xac9b0e57, /* cps = 2356.00, nrm = 32, interval = 149.75 */ -/* 134 */ 0xaccd0e3f, /* cps = 2456.00, nrm = 32, interval = 143.75 */ -/* 135 */ 0xacff0e28, /* cps = 2556.00, nrm = 32, interval = 138.00 */ -/* 136 */ 0xad350e12, /* cps = 2664.00, nrm = 32, interval = 132.50 */ -/* 137 */ 0xad6d0bf9, /* cps = 2776.00, nrm = 32, interval = 127.12 */ -/* 138 */ 0xada70bd0, /* cps = 2892.00, nrm = 32, interval = 122.00 */ -/* 139 */ 0xade30ba9, /* cps = 3012.00, nrm = 32, interval = 117.12 */ -/* 140 */ 0xae230b83, /* cps = 3140.00, nrm = 32, interval = 112.38 */ -/* 141 */ 0xae650b5f, /* cps = 3272.00, nrm = 32, interval = 107.88 */ -/* 142 */ 0xaeab0b3c, /* cps = 3412.00, nrm = 32, interval = 103.50 */ -/* 143 */ 0xaef10b1b, /* cps = 3552.00, nrm = 32, interval = 99.38 */ -/* 144 */ 0xaf3b0afb, /* cps = 3700.00, nrm = 32, interval = 95.38 */ -/* 145 */ 0xaf8b0adc, /* cps = 3860.00, nrm = 32, interval = 91.50 */ -/* 146 */ 0xafd90abf, /* cps = 4016.00, nrm = 32, interval = 87.88 */ -/* 147 */ 0xb0170aa3, /* cps = 4184.00, nrm = 32, interval = 84.38 */ -/* 148 */ 0xb0430a87, /* cps = 4360.00, nrm = 32, interval = 80.88 */ -/* 149 */ 0xb0710a6d, /* cps = 4544.00, nrm = 32, interval = 77.62 */ -/* 150 */ 0xb0a10a54, /* cps = 4736.00, nrm = 32, interval = 74.50 */ -/* 151 */ 0xb0d30a3c, /* cps = 4936.00, nrm = 32, interval = 71.50 */ -/* 152 */ 0xb1070a25, /* cps = 5144.00, nrm = 32, interval = 68.62 */ -/* 153 */ 0xb13d0a0f, /* cps = 5360.00, nrm = 32, interval = 65.88 */ -/* 154 */ 0xb17507f4, /* cps = 5584.00, nrm = 32, interval = 63.25 */ -/* 155 */ 0xb1af07cb, /* cps = 5816.00, nrm = 32, interval = 60.69 */ -/* 156 */ 0xb1eb07a4, /* cps = 6056.00, nrm = 32, interval = 58.25 */ -/* 157 */ 0xb22b077f, /* cps = 6312.00, nrm = 32, interval = 55.94 */ -/* 158 */ 0xb26d075b, /* cps = 6576.00, nrm = 32, interval = 53.69 */ -/* 159 */ 0xb2b30738, /* cps = 6856.00, nrm = 32, interval = 51.50 */ -/* 160 */ 0xb2fb0717, /* cps = 7144.00, nrm = 32, interval = 49.44 */ -/* 161 */ 0xb34506f7, /* cps = 7440.00, nrm = 32, interval = 47.44 */ -/* 162 */ 0xb39306d9, /* cps = 7752.00, nrm = 32, interval = 45.56 */ -/* 163 */ 0xb3e506bb, /* cps = 8080.00, nrm = 32, interval = 43.69 */ -/* 164 */ 0xb41d069f, /* cps = 8416.00, nrm = 32, interval = 41.94 */ -/* 165 */ 0xb4490684, /* cps = 8768.00, nrm = 32, interval = 40.25 */ -/* 166 */ 0xb477066a, /* cps = 9136.00, nrm = 32, interval = 38.62 */ -/* 167 */ 0xb4a70651, /* cps = 9520.00, nrm = 32, interval = 37.06 */ -/* 168 */ 0xb4d90639, /* cps = 9920.00, nrm = 32, interval = 35.56 */ -/* 169 */ 0xb50d0622, /* cps = 10336.00, nrm = 32, interval = 34.12 */ -/* 170 */ 0xb545060c, /* cps = 10784.00, nrm = 32, interval = 32.75 */ -/* 171 */ 0xb57b03ef, /* cps = 11216.00, nrm = 32, interval = 31.47 */ -/* 172 */ 0xb5b503c7, /* cps = 11680.00, nrm = 32, interval = 30.22 */ -/* 173 */ 0xb5f303a0, /* cps = 12176.00, nrm = 32, interval = 29.00 */ -/* 174 */ 0xb633037a, /* cps = 12688.00, nrm = 32, interval = 27.81 */ -/* 175 */ 0xb6750357, /* cps = 13216.00, nrm = 32, interval = 26.72 */ -/* 176 */ 0xb6bb0334, /* cps = 13776.00, nrm = 32, interval = 25.62 */ -/* 177 */ 0xb7030313, /* cps = 14352.00, nrm = 32, interval = 24.59 */ -/* 178 */ 0xb74f02f3, /* cps = 14960.00, nrm = 32, interval = 23.59 */ -/* 179 */ 0xb79d02d5, /* cps = 15584.00, nrm = 32, interval = 22.66 */ -/* 180 */ 0xb7ed02b8, /* cps = 16224.00, nrm = 32, interval = 21.75 */ -/* 181 */ 0xb821029c, /* cps = 16896.00, nrm = 32, interval = 20.88 */ -/* 182 */ 0xb84f0281, /* cps = 17632.00, nrm = 32, interval = 20.03 */ -/* 183 */ 0xb87d0267, /* cps = 18368.00, nrm = 32, interval = 19.22 */ -/* 184 */ 0xb8ad024e, /* cps = 19136.00, nrm = 32, interval = 18.44 */ -/* 185 */ 0xb8dd0237, /* cps = 19904.00, nrm = 32, interval = 17.72 */ -/* 186 */ 0xb9130220, /* cps = 20768.00, nrm = 32, interval = 17.00 */ -/* 187 */ 0xb949020a, /* cps = 21632.00, nrm = 32, interval = 16.31 */ -/* 188 */ 0xb98301f5, /* cps = 22560.00, nrm = 32, interval = 15.66 */ -/* 189 */ 0xb9bd01e1, /* cps = 23488.00, nrm = 32, interval = 15.03 */ -/* 190 */ 0xb9fd01cd, /* cps = 24512.00, nrm = 32, interval = 14.41 */ -/* 191 */ 0xba3b01bb, /* cps = 25504.00, nrm = 32, interval = 13.84 */ -/* 192 */ 0xba7f01a9, /* cps = 26592.00, nrm = 32, interval = 13.28 */ -/* 193 */ 0xbac30198, /* cps = 27680.00, nrm = 32, interval = 12.75 */ -/* 194 */ 0xbb0f0187, /* cps = 28896.00, nrm = 32, interval = 12.22 */ -/* 195 */ 0xbb570178, /* cps = 30048.00, nrm = 32, interval = 11.75 */ -/* 196 */ 0xbbab0168, /* cps = 31392.00, nrm = 32, interval = 11.25 */ -/* 197 */ 0xbbf9015a, /* cps = 32640.00, nrm = 32, interval = 10.81 */ -/* 198 */ 0xbc27014c, /* cps = 33984.00, nrm = 32, interval = 10.38 */ -/* 199 */ 0xbc53013f, /* cps = 35392.00, nrm = 32, interval = 9.97 */ -/* 200 */ 0xbc830132, /* cps = 36928.00, nrm = 32, interval = 9.56 */ -/* 201 */ 0xbcb50125, /* cps = 38528.00, nrm = 32, interval = 9.16 */ -/* 202 */ 0xbce5011a, /* cps = 40064.00, nrm = 32, interval = 8.81 */ -/* 203 */ 0xbd1d010e, /* cps = 41856.00, nrm = 32, interval = 8.44 */ -/* 204 */ 0xbd530103, /* cps = 43584.00, nrm = 32, interval = 8.09 */ -/* 205 */ 0xbd8b00f9, /* cps = 45376.00, nrm = 32, interval = 7.78 */ -/* 206 */ 0xbdc500ef, /* cps = 47232.00, nrm = 32, interval = 7.47 */ -/* 207 */ 0xbe0700e5, /* cps = 49344.00, nrm = 32, interval = 7.16 */ -/* 208 */ 0xbe4500dc, /* cps = 51328.00, nrm = 32, interval = 6.88 */ -/* 209 */ 0xbe8900d3, /* cps = 53504.00, nrm = 32, interval = 6.59 */ -/* 210 */ 0xbecb00cb, /* cps = 55616.00, nrm = 32, interval = 6.34 */ -/* 211 */ 0xbf1d00c2, /* cps = 58240.00, nrm = 32, interval = 6.06 */ -/* 212 */ 0xbf6100bb, /* cps = 60416.00, nrm = 32, interval = 5.84 */ -/* 213 */ 0xbfb500b3, /* cps = 63104.00, nrm = 32, interval = 5.59 */ -/* 214 */ 0xc00300ac, /* cps = 65664.00, nrm = 32, interval = 5.38 */ -/* 215 */ 0xc02f00a5, /* cps = 68480.00, nrm = 32, interval = 5.16 */ -/* 216 */ 0xc05d009e, /* cps = 71424.00, nrm = 32, interval = 4.94 */ -/* 217 */ 0xc0890098, /* cps = 74240.00, nrm = 32, interval = 4.75 */ -/* 218 */ 0xc0b90092, /* cps = 77312.00, nrm = 32, interval = 4.56 */ -/* 219 */ 0xc0ed008c, /* cps = 80640.00, nrm = 32, interval = 4.38 */ -/* 220 */ 0xc1250086, /* cps = 84224.00, nrm = 32, interval = 4.19 */ -/* 221 */ 0xc1590081, /* cps = 87552.00, nrm = 32, interval = 4.03 */ -/* 222 */ 0xc191007c, /* cps = 91136.00, nrm = 32, interval = 3.88 */ -/* 223 */ 0xc1cd0077, /* cps = 94976.00, nrm = 32, interval = 3.72 */ -/* 224 */ 0xc20d0072, /* cps = 99072.00, nrm = 32, interval = 3.56 */ -/* 225 */ 0xc255006d, /* cps = 103680.00, nrm = 32, interval = 3.41 */ -/* 226 */ 0xc2910069, /* cps = 107520.00, nrm = 32, interval = 3.28 */ -/* 227 */ 0xc2d50065, /* cps = 111872.00, nrm = 32, interval = 3.16 */ -/* 228 */ 0xc32f0060, /* cps = 117632.00, nrm = 32, interval = 3.00 */ -/* 229 */ 0xc36b005d, /* cps = 121472.00, nrm = 32, interval = 2.91 */ -/* 230 */ 0xc3c10059, /* cps = 126976.00, nrm = 32, interval = 2.78 */ -/* 231 */ 0xc40f0055, /* cps = 132864.00, nrm = 32, interval = 2.66 */ -/* 232 */ 0xc4350052, /* cps = 137728.00, nrm = 32, interval = 2.56 */ -/* 233 */ 0xc46d004e, /* cps = 144896.00, nrm = 32, interval = 2.44 */ -/* 234 */ 0xc499004b, /* cps = 150528.00, nrm = 32, interval = 2.34 */ -/* 235 */ 0xc4cb0048, /* cps = 156928.00, nrm = 32, interval = 2.25 */ -/* 236 */ 0xc4ff0045, /* cps = 163584.00, nrm = 32, interval = 2.16 */ -/* 237 */ 0xc5250043, /* cps = 168448.00, nrm = 32, interval = 2.09 */ -/* 238 */ 0xc5630040, /* cps = 176384.00, nrm = 32, interval = 2.00 */ -/* 239 */ 0xc5a7003d, /* cps = 185088.00, nrm = 32, interval = 1.91 */ -/* 240 */ 0xc5d9003b, /* cps = 191488.00, nrm = 32, interval = 1.84 */ -/* 241 */ 0xc6290038, /* cps = 201728.00, nrm = 32, interval = 1.75 */ -/* 242 */ 0xc6630036, /* cps = 209152.00, nrm = 32, interval = 1.69 */ -/* 243 */ 0xc6a30034, /* cps = 217344.00, nrm = 32, interval = 1.62 */ -/* 244 */ 0xc6e70032, /* cps = 226048.00, nrm = 32, interval = 1.56 */ -/* 245 */ 0xc72f0030, /* cps = 235264.00, nrm = 32, interval = 1.50 */ -/* 246 */ 0xc77f002e, /* cps = 245504.00, nrm = 32, interval = 1.44 */ -/* 247 */ 0xc7d7002c, /* cps = 256768.00, nrm = 32, interval = 1.38 */ -/* 248 */ 0xc81b002a, /* cps = 268800.00, nrm = 32, interval = 1.31 */ -/* 249 */ 0xc84f0028, /* cps = 282112.00, nrm = 32, interval = 1.25 */ -/* 250 */ 0xc86d0027, /* cps = 289792.00, nrm = 32, interval = 1.22 */ -/* 251 */ 0xc8a90025, /* cps = 305152.00, nrm = 32, interval = 1.16 */ -/* 252 */ 0xc8cb0024, /* cps = 313856.00, nrm = 32, interval = 1.12 */ -/* 253 */ 0xc9130022, /* cps = 332288.00, nrm = 32, interval = 1.06 */ -/* 254 */ 0xc9390021, /* cps = 342016.00, nrm = 32, interval = 1.03 */ -/* 255 */ 0xc9630020, /* cps = 352768.00, nrm = 32, interval = 1.00 */ -}; - -static unsigned char rate_to_log[] = -{ -/* 1.00 => 0 */ 0x00, /* => 10.02 */ -/* 1.06 => 0 */ 0x00, /* => 10.02 */ -/* 1.12 => 0 */ 0x00, /* => 10.02 */ -/* 1.19 => 0 */ 0x00, /* => 10.02 */ -/* 1.25 => 0 */ 0x00, /* => 10.02 */ -/* 1.31 => 0 */ 0x00, /* => 10.02 */ -/* 1.38 => 0 */ 0x00, /* => 10.02 */ -/* 1.44 => 0 */ 0x00, /* => 10.02 */ -/* 1.50 => 0 */ 0x00, /* => 10.02 */ -/* 1.56 => 0 */ 0x00, /* => 10.02 */ -/* 1.62 => 0 */ 0x00, /* => 10.02 */ -/* 1.69 => 0 */ 0x00, /* => 10.02 */ -/* 1.75 => 0 */ 0x00, /* => 10.02 */ -/* 1.81 => 0 */ 0x00, /* => 10.02 */ -/* 1.88 => 0 */ 0x00, /* => 10.02 */ -/* 1.94 => 0 */ 0x00, /* => 10.02 */ -/* 2.00 => 0 */ 0x00, /* => 10.02 */ -/* 2.12 => 0 */ 0x00, /* => 10.02 */ -/* 2.25 => 0 */ 0x00, /* => 10.02 */ -/* 2.38 => 0 */ 0x00, /* => 10.02 */ -/* 2.50 => 0 */ 0x00, /* => 10.02 */ -/* 2.62 => 0 */ 0x00, /* => 10.02 */ -/* 2.75 => 0 */ 0x00, /* => 10.02 */ -/* 2.88 => 0 */ 0x00, /* => 10.02 */ -/* 3.00 => 0 */ 0x00, /* => 10.02 */ -/* 3.12 => 0 */ 0x00, /* => 10.02 */ -/* 3.25 => 0 */ 0x00, /* => 10.02 */ -/* 3.38 => 0 */ 0x00, /* => 10.02 */ -/* 3.50 => 0 */ 0x00, /* => 10.02 */ -/* 3.62 => 0 */ 0x00, /* => 10.02 */ -/* 3.75 => 0 */ 0x00, /* => 10.02 */ -/* 3.88 => 0 */ 0x00, /* => 10.02 */ -/* 4.00 => 0 */ 0x00, /* => 10.02 */ -/* 4.25 => 0 */ 0x00, /* => 10.02 */ -/* 4.50 => 0 */ 0x00, /* => 10.02 */ -/* 4.75 => 0 */ 0x00, /* => 10.02 */ -/* 5.00 => 0 */ 0x00, /* => 10.02 */ -/* 5.25 => 0 */ 0x00, /* => 10.02 */ -/* 5.50 => 0 */ 0x00, /* => 10.02 */ -/* 5.75 => 0 */ 0x00, /* => 10.02 */ -/* 6.00 => 0 */ 0x00, /* => 10.02 */ -/* 6.25 => 0 */ 0x00, /* => 10.02 */ -/* 6.50 => 0 */ 0x00, /* => 10.02 */ -/* 6.75 => 0 */ 0x00, /* => 10.02 */ -/* 7.00 => 0 */ 0x00, /* => 10.02 */ -/* 7.25 => 0 */ 0x00, /* => 10.02 */ -/* 7.50 => 0 */ 0x00, /* => 10.02 */ -/* 7.75 => 0 */ 0x00, /* => 10.02 */ -/* 8.00 => 0 */ 0x00, /* => 10.02 */ -/* 8.50 => 0 */ 0x00, /* => 10.02 */ -/* 9.00 => 0 */ 0x00, /* => 10.02 */ -/* 9.50 => 0 */ 0x00, /* => 10.02 */ -/* 10.00 => 0 */ 0x00, /* => 10.02 */ -/* 10.50 => 1 */ 0x01, /* => 10.42 */ -/* 11.00 => 2 */ 0x02, /* => 10.86 */ -/* 11.50 => 3 */ 0x03, /* => 11.31 */ -/* 12.00 => 4 */ 0x04, /* => 11.78 */ -/* 12.50 => 5 */ 0x05, /* => 12.28 */ -/* 13.00 => 6 */ 0x06, /* => 12.80 */ -/* 13.50 => 7 */ 0x07, /* => 13.33 */ -/* 14.00 => 8 */ 0x08, /* => 13.89 */ -/* 14.50 => 9 */ 0x09, /* => 14.48 */ -/* 15.00 => 9 */ 0x09, /* => 14.48 */ -/* 15.50 => 10 */ 0x0a, /* => 15.08 */ -/* 16.00 => 11 */ 0x0b, /* => 15.72 */ -/* 17.00 => 12 */ 0x0c, /* => 16.38 */ -/* 18.00 => 14 */ 0x0e, /* => 17.75 */ -/* 19.00 => 15 */ 0x0f, /* => 18.50 */ -/* 20.00 => 16 */ 0x10, /* => 19.28 */ -/* 21.00 => 18 */ 0x12, /* => 20.94 */ -/* 22.00 => 19 */ 0x13, /* => 21.81 */ -/* 23.00 => 20 */ 0x14, /* => 22.75 */ -/* 24.00 => 21 */ 0x15, /* => 23.69 */ -/* 25.00 => 22 */ 0x16, /* => 24.69 */ -/* 26.00 => 23 */ 0x17, /* => 25.72 */ -/* 27.00 => 24 */ 0x18, /* => 26.81 */ -/* 28.00 => 25 */ 0x19, /* => 27.94 */ -/* 29.00 => 25 */ 0x19, /* => 27.94 */ -/* 30.00 => 26 */ 0x1a, /* => 29.09 */ -/* 31.00 => 27 */ 0x1b, /* => 30.31 */ -/* 32.00 => 28 */ 0x1c, /* => 31.56 */ -/* 34.00 => 29 */ 0x1d, /* => 32.94 */ -/* 36.00 => 31 */ 0x1f, /* => 35.69 */ -/* 38.00 => 32 */ 0x20, /* => 37.19 */ -/* 40.00 => 33 */ 0x21, /* => 38.75 */ -/* 42.00 => 34 */ 0x22, /* => 40.38 */ -/* 44.00 => 36 */ 0x24, /* => 43.88 */ -/* 46.00 => 37 */ 0x25, /* => 45.69 */ -/* 48.00 => 38 */ 0x26, /* => 47.62 */ -/* 50.00 => 39 */ 0x27, /* => 49.62 */ -/* 52.00 => 40 */ 0x28, /* => 51.69 */ -/* 54.00 => 41 */ 0x29, /* => 53.88 */ -/* 56.00 => 41 */ 0x29, /* => 53.88 */ -/* 58.00 => 42 */ 0x2a, /* => 56.12 */ -/* 60.00 => 43 */ 0x2b, /* => 58.44 */ -/* 62.00 => 44 */ 0x2c, /* => 60.94 */ -/* 64.00 => 45 */ 0x2d, /* => 63.50 */ -/* 68.00 => 46 */ 0x2e, /* => 66.12 */ -/* 72.00 => 48 */ 0x30, /* => 71.88 */ -/* 76.00 => 49 */ 0x31, /* => 74.75 */ -/* 80.00 => 50 */ 0x32, /* => 78.00 */ -/* 84.00 => 51 */ 0x33, /* => 81.25 */ -/* 88.00 => 52 */ 0x34, /* => 84.62 */ -/* 92.00 => 54 */ 0x36, /* => 91.88 */ -/* 96.00 => 55 */ 0x37, /* => 95.75 */ -/* 100.00 => 56 */ 0x38, /* => 99.75 */ -/* 104.00 => 56 */ 0x38, /* => 99.75 */ -/* 108.00 => 57 */ 0x39, /* => 104.00 */ -/* 112.00 => 58 */ 0x3a, /* => 108.25 */ -/* 116.00 => 59 */ 0x3b, /* => 112.88 */ -/* 120.00 => 60 */ 0x3c, /* => 117.50 */ -/* 124.00 => 61 */ 0x3d, /* => 122.38 */ -/* 128.00 => 62 */ 0x3e, /* => 127.50 */ -/* 136.00 => 63 */ 0x3f, /* => 132.75 */ -/* 144.00 => 64 */ 0x40, /* => 138.50 */ -/* 152.00 => 66 */ 0x42, /* => 150.25 */ -/* 160.00 => 67 */ 0x43, /* => 156.75 */ -/* 168.00 => 68 */ 0x44, /* => 163.50 */ -/* 176.00 => 69 */ 0x45, /* => 170.00 */ -/* 184.00 => 70 */ 0x46, /* => 177.25 */ -/* 192.00 => 71 */ 0x47, /* => 184.50 */ -/* 200.00 => 72 */ 0x48, /* => 192.25 */ -/* 208.00 => 73 */ 0x49, /* => 200.25 */ -/* 216.00 => 74 */ 0x4a, /* => 208.75 */ -/* 224.00 => 75 */ 0x4b, /* => 217.75 */ -/* 232.00 => 76 */ 0x4c, /* => 226.75 */ -/* 240.00 => 77 */ 0x4d, /* => 236.25 */ -/* 248.00 => 78 */ 0x4e, /* => 246.25 */ -/* 256.00 => 78 */ 0x4e, /* => 246.25 */ -/* 272.00 => 80 */ 0x50, /* => 267.50 */ -/* 288.00 => 81 */ 0x51, /* => 278.50 */ -/* 304.00 => 83 */ 0x53, /* => 302.00 */ -/* 320.00 => 84 */ 0x54, /* => 315.00 */ -/* 336.00 => 85 */ 0x55, /* => 328.00 */ -/* 352.00 => 86 */ 0x56, /* => 342.00 */ -/* 368.00 => 87 */ 0x57, /* => 356.00 */ -/* 384.00 => 88 */ 0x58, /* => 371.00 */ -/* 400.00 => 89 */ 0x59, /* => 386.50 */ -/* 416.00 => 90 */ 0x5a, /* => 403.00 */ -/* 432.00 => 91 */ 0x5b, /* => 419.50 */ -/* 448.00 => 92 */ 0x5c, /* => 437.50 */ -/* 464.00 => 93 */ 0x5d, /* => 455.50 */ -/* 480.00 => 94 */ 0x5e, /* => 475.00 */ -/* 496.00 => 95 */ 0x5f, /* => 495.00 */ -/* 512.00 => 95 */ 0x5f, /* => 495.00 */ -/* 544.00 => 97 */ 0x61, /* => 537.00 */ -/* 576.00 => 98 */ 0x62, /* => 559.00 */ -/* 608.00 => 100 */ 0x64, /* => 607.00 */ -/* 640.00 => 101 */ 0x65, /* => 632.00 */ -/* 672.00 => 102 */ 0x66, /* => 660.00 */ -/* 704.00 => 103 */ 0x67, /* => 687.00 */ -/* 736.00 => 104 */ 0x68, /* => 716.00 */ -/* 768.00 => 105 */ 0x69, /* => 746.00 */ -/* 800.00 => 106 */ 0x6a, /* => 777.00 */ -/* 832.00 => 107 */ 0x6b, /* => 810.00 */ -/* 864.00 => 108 */ 0x6c, /* => 843.00 */ -/* 896.00 => 109 */ 0x6d, /* => 879.00 */ -/* 928.00 => 110 */ 0x6e, /* => 916.00 */ -/* 960.00 => 111 */ 0x6f, /* => 954.00 */ -/* 992.00 => 111 */ 0x6f, /* => 954.00 */ -/* 1024.00 => 112 */ 0x70, /* => 994.00 */ -/* 1088.00 => 114 */ 0x72, /* => 1080.00 */ -/* 1152.00 => 115 */ 0x73, /* => 1124.00 */ -/* 1216.00 => 116 */ 0x74, /* => 1172.00 */ -/* 1280.00 => 118 */ 0x76, /* => 1272.00 */ -/* 1344.00 => 119 */ 0x77, /* => 1326.00 */ -/* 1408.00 => 120 */ 0x78, /* => 1382.00 */ -/* 1472.00 => 121 */ 0x79, /* => 1440.00 */ -/* 1536.00 => 122 */ 0x7a, /* => 1498.00 */ -/* 1600.00 => 123 */ 0x7b, /* => 1562.00 */ -/* 1664.00 => 124 */ 0x7c, /* => 1628.00 */ -/* 1728.00 => 125 */ 0x7d, /* => 1696.00 */ -/* 1792.00 => 126 */ 0x7e, /* => 1768.00 */ -/* 1856.00 => 127 */ 0x7f, /* => 1842.00 */ -/* 1920.00 => 128 */ 0x80, /* => 1918.00 */ -/* 1984.00 => 128 */ 0x80, /* => 1918.00 */ -/* 2048.00 => 129 */ 0x81, /* => 2000.00 */ -/* 2176.00 => 131 */ 0x83, /* => 2168.00 */ -/* 2304.00 => 132 */ 0x84, /* => 2264.00 */ -/* 2432.00 => 133 */ 0x85, /* => 2356.00 */ -/* 2560.00 => 135 */ 0x87, /* => 2556.00 */ -/* 2688.00 => 136 */ 0x88, /* => 2664.00 */ -/* 2816.00 => 137 */ 0x89, /* => 2776.00 */ -/* 2944.00 => 138 */ 0x8a, /* => 2892.00 */ -/* 3072.00 => 139 */ 0x8b, /* => 3012.00 */ -/* 3200.00 => 140 */ 0x8c, /* => 3140.00 */ -/* 3328.00 => 141 */ 0x8d, /* => 3272.00 */ -/* 3456.00 => 142 */ 0x8e, /* => 3412.00 */ -/* 3584.00 => 143 */ 0x8f, /* => 3552.00 */ -/* 3712.00 => 144 */ 0x90, /* => 3700.00 */ -/* 3840.00 => 144 */ 0x90, /* => 3700.00 */ -/* 3968.00 => 145 */ 0x91, /* => 3860.00 */ -/* 4096.00 => 146 */ 0x92, /* => 4016.00 */ -/* 4352.00 => 147 */ 0x93, /* => 4184.00 */ -/* 4608.00 => 149 */ 0x95, /* => 4544.00 */ -/* 4864.00 => 150 */ 0x96, /* => 4736.00 */ -/* 5120.00 => 151 */ 0x97, /* => 4936.00 */ -/* 5376.00 => 153 */ 0x99, /* => 5360.00 */ -/* 5632.00 => 154 */ 0x9a, /* => 5584.00 */ -/* 5888.00 => 155 */ 0x9b, /* => 5816.00 */ -/* 6144.00 => 156 */ 0x9c, /* => 6056.00 */ -/* 6400.00 => 157 */ 0x9d, /* => 6312.00 */ -/* 6656.00 => 158 */ 0x9e, /* => 6576.00 */ -/* 6912.00 => 159 */ 0x9f, /* => 6856.00 */ -/* 7168.00 => 160 */ 0xa0, /* => 7144.00 */ -/* 7424.00 => 160 */ 0xa0, /* => 7144.00 */ -/* 7680.00 => 161 */ 0xa1, /* => 7440.00 */ -/* 7936.00 => 162 */ 0xa2, /* => 7752.00 */ -/* 8192.00 => 163 */ 0xa3, /* => 8080.00 */ -/* 8704.00 => 164 */ 0xa4, /* => 8416.00 */ -/* 9216.00 => 166 */ 0xa6, /* => 9136.00 */ -/* 9728.00 => 167 */ 0xa7, /* => 9520.00 */ -/* 10240.00 => 168 */ 0xa8, /* => 9920.00 */ -/* 10752.00 => 169 */ 0xa9, /* => 10336.00 */ -/* 11264.00 => 171 */ 0xab, /* => 11216.00 */ -/* 11776.00 => 172 */ 0xac, /* => 11680.00 */ -/* 12288.00 => 173 */ 0xad, /* => 12176.00 */ -/* 12800.00 => 174 */ 0xae, /* => 12688.00 */ -/* 13312.00 => 175 */ 0xaf, /* => 13216.00 */ -/* 13824.00 => 176 */ 0xb0, /* => 13776.00 */ -/* 14336.00 => 176 */ 0xb0, /* => 13776.00 */ -/* 14848.00 => 177 */ 0xb1, /* => 14352.00 */ -/* 15360.00 => 178 */ 0xb2, /* => 14960.00 */ -/* 15872.00 => 179 */ 0xb3, /* => 15584.00 */ -/* 16384.00 => 180 */ 0xb4, /* => 16224.00 */ -/* 17408.00 => 181 */ 0xb5, /* => 16896.00 */ -/* 18432.00 => 183 */ 0xb7, /* => 18368.00 */ -/* 19456.00 => 184 */ 0xb8, /* => 19136.00 */ -/* 20480.00 => 185 */ 0xb9, /* => 19904.00 */ -/* 21504.00 => 186 */ 0xba, /* => 20768.00 */ -/* 22528.00 => 187 */ 0xbb, /* => 21632.00 */ -/* 23552.00 => 189 */ 0xbd, /* => 23488.00 */ -/* 24576.00 => 190 */ 0xbe, /* => 24512.00 */ -/* 25600.00 => 191 */ 0xbf, /* => 25504.00 */ -/* 26624.00 => 192 */ 0xc0, /* => 26592.00 */ -/* 27648.00 => 192 */ 0xc0, /* => 26592.00 */ -/* 28672.00 => 193 */ 0xc1, /* => 27680.00 */ -/* 29696.00 => 194 */ 0xc2, /* => 28896.00 */ -/* 30720.00 => 195 */ 0xc3, /* => 30048.00 */ -/* 31744.00 => 196 */ 0xc4, /* => 31392.00 */ -/* 32768.00 => 197 */ 0xc5, /* => 32640.00 */ -/* 34816.00 => 198 */ 0xc6, /* => 33984.00 */ -/* 36864.00 => 199 */ 0xc7, /* => 35392.00 */ -/* 38912.00 => 201 */ 0xc9, /* => 38528.00 */ -/* 40960.00 => 202 */ 0xca, /* => 40064.00 */ -/* 43008.00 => 203 */ 0xcb, /* => 41856.00 */ -/* 45056.00 => 204 */ 0xcc, /* => 43584.00 */ -/* 47104.00 => 205 */ 0xcd, /* => 45376.00 */ -/* 49152.00 => 206 */ 0xce, /* => 47232.00 */ -/* 51200.00 => 207 */ 0xcf, /* => 49344.00 */ -/* 53248.00 => 208 */ 0xd0, /* => 51328.00 */ -/* 55296.00 => 209 */ 0xd1, /* => 53504.00 */ -/* 57344.00 => 210 */ 0xd2, /* => 55616.00 */ -/* 59392.00 => 211 */ 0xd3, /* => 58240.00 */ -/* 61440.00 => 212 */ 0xd4, /* => 60416.00 */ -/* 63488.00 => 213 */ 0xd5, /* => 63104.00 */ -/* 65536.00 => 213 */ 0xd5, /* => 63104.00 */ -/* 69632.00 => 215 */ 0xd7, /* => 68480.00 */ -/* 73728.00 => 216 */ 0xd8, /* => 71424.00 */ -/* 77824.00 => 218 */ 0xda, /* => 77312.00 */ -/* 81920.00 => 219 */ 0xdb, /* => 80640.00 */ -/* 86016.00 => 220 */ 0xdc, /* => 84224.00 */ -/* 90112.00 => 221 */ 0xdd, /* => 87552.00 */ -/* 94208.00 => 222 */ 0xde, /* => 91136.00 */ -/* 98304.00 => 223 */ 0xdf, /* => 94976.00 */ -/* 102400.00 => 224 */ 0xe0, /* => 99072.00 */ -/* 106496.00 => 225 */ 0xe1, /* => 103680.00 */ -/* 110592.00 => 226 */ 0xe2, /* => 107520.00 */ -/* 114688.00 => 227 */ 0xe3, /* => 111872.00 */ -/* 118784.00 => 228 */ 0xe4, /* => 117632.00 */ -/* 122880.00 => 229 */ 0xe5, /* => 121472.00 */ -/* 126976.00 => 229 */ 0xe5, /* => 121472.00 */ -/* 131072.00 => 230 */ 0xe6, /* => 126976.00 */ -/* 139264.00 => 232 */ 0xe8, /* => 137728.00 */ -/* 147456.00 => 233 */ 0xe9, /* => 144896.00 */ -/* 155648.00 => 234 */ 0xea, /* => 150528.00 */ -/* 163840.00 => 236 */ 0xec, /* => 163584.00 */ -/* 172032.00 => 237 */ 0xed, /* => 168448.00 */ -/* 180224.00 => 238 */ 0xee, /* => 176384.00 */ -/* 188416.00 => 239 */ 0xef, /* => 185088.00 */ -/* 196608.00 => 240 */ 0xf0, /* => 191488.00 */ -/* 204800.00 => 241 */ 0xf1, /* => 201728.00 */ -/* 212992.00 => 242 */ 0xf2, /* => 209152.00 */ -/* 221184.00 => 243 */ 0xf3, /* => 217344.00 */ -/* 229376.00 => 244 */ 0xf4, /* => 226048.00 */ -/* 237568.00 => 245 */ 0xf5, /* => 235264.00 */ -/* 245760.00 => 246 */ 0xf6, /* => 245504.00 */ -/* 253952.00 => 246 */ 0xf6, /* => 245504.00 */ -/* 262144.00 => 247 */ 0xf7, /* => 256768.00 */ -/* 278528.00 => 248 */ 0xf8, /* => 268800.00 */ -/* 294912.00 => 250 */ 0xfa, /* => 289792.00 */ -/* 311296.00 => 251 */ 0xfb, /* => 305152.00 */ -/* 327680.00 => 252 */ 0xfc, /* => 313856.00 */ -/* 344064.00 => 254 */ 0xfe, /* => 342016.00 */ -/* 360448.00 => 255 */ 0xff, /* => 352768.00 */ -/* 376832.00 => 255 */ 0xff, /* => 352768.00 */ -/* 393216.00 => 255 */ 0xff, /* => 352768.00 */ -/* 409600.00 => 255 */ 0xff, /* => 352768.00 */ -/* 425984.00 => 255 */ 0xff, /* => 352768.00 */ -/* 442368.00 => 255 */ 0xff, /* => 352768.00 */ -/* 458752.00 => 255 */ 0xff, /* => 352768.00 */ -/* 475136.00 => 255 */ 0xff, /* => 352768.00 */ -/* 491520.00 => 255 */ 0xff, /* => 352768.00 */ -/* 507904.00 => 255 */ 0xff, /* => 352768.00 */ -/* 524288.00 => 255 */ 0xff, /* => 352768.00 */ -/* 557056.00 => 255 */ 0xff, /* => 352768.00 */ -/* 589824.00 => 255 */ 0xff, /* => 352768.00 */ -/* 622592.00 => 255 */ 0xff, /* => 352768.00 */ -/* 655360.00 => 255 */ 0xff, /* => 352768.00 */ -/* 688128.00 => 255 */ 0xff, /* => 352768.00 */ -/* 720896.00 => 255 */ 0xff, /* => 352768.00 */ -/* 753664.00 => 255 */ 0xff, /* => 352768.00 */ -/* 786432.00 => 255 */ 0xff, /* => 352768.00 */ -/* 819200.00 => 255 */ 0xff, /* => 352768.00 */ -/* 851968.00 => 255 */ 0xff, /* => 352768.00 */ -/* 884736.00 => 255 */ 0xff, /* => 352768.00 */ -/* 917504.00 => 255 */ 0xff, /* => 352768.00 */ -/* 950272.00 => 255 */ 0xff, /* => 352768.00 */ -/* 983040.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1015808.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1048576.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1114112.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1179648.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1245184.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1310720.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1376256.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1441792.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1507328.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1572864.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1638400.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1703936.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1769472.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1835008.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1900544.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1966080.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2031616.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2097152.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2228224.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2359296.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2490368.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2621440.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2752512.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2883584.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3014656.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3145728.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3276800.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3407872.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3538944.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3670016.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3801088.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3932160.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4063232.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4194304.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4456448.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4718592.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4980736.00 => 255 */ 0xff, /* => 352768.00 */ -/* 5242880.00 => 255 */ 0xff, /* => 352768.00 */ -/* 5505024.00 => 255 */ 0xff, /* => 352768.00 */ -/* 5767168.00 => 255 */ 0xff, /* => 352768.00 */ -/* 6029312.00 => 255 */ 0xff, /* => 352768.00 */ -/* 6291456.00 => 255 */ 0xff, /* => 352768.00 */ -/* 6553600.00 => 255 */ 0xff, /* => 352768.00 */ -/* 6815744.00 => 255 */ 0xff, /* => 352768.00 */ -/* 7077888.00 => 255 */ 0xff, /* => 352768.00 */ -/* 7340032.00 => 255 */ 0xff, /* => 352768.00 */ -/* 7602176.00 => 255 */ 0xff, /* => 352768.00 */ -/* 7864320.00 => 255 */ 0xff, /* => 352768.00 */ -/* 8126464.00 => 255 */ 0xff, /* => 352768.00 */ -/* 8388608.00 => 255 */ 0xff, /* => 352768.00 */ -/* 8912896.00 => 255 */ 0xff, /* => 352768.00 */ -/* 9437184.00 => 255 */ 0xff, /* => 352768.00 */ -/* 9961472.00 => 255 */ 0xff, /* => 352768.00 */ -/* 10485760.00 => 255 */ 0xff, /* => 352768.00 */ -/* 11010048.00 => 255 */ 0xff, /* => 352768.00 */ -/* 11534336.00 => 255 */ 0xff, /* => 352768.00 */ -/* 12058624.00 => 255 */ 0xff, /* => 352768.00 */ -/* 12582912.00 => 255 */ 0xff, /* => 352768.00 */ -/* 13107200.00 => 255 */ 0xff, /* => 352768.00 */ -/* 13631488.00 => 255 */ 0xff, /* => 352768.00 */ -/* 14155776.00 => 255 */ 0xff, /* => 352768.00 */ -/* 14680064.00 => 255 */ 0xff, /* => 352768.00 */ -/* 15204352.00 => 255 */ 0xff, /* => 352768.00 */ -/* 15728640.00 => 255 */ 0xff, /* => 352768.00 */ -/* 16252928.00 => 255 */ 0xff, /* => 352768.00 */ -/* 16777216.00 => 255 */ 0xff, /* => 352768.00 */ -/* 17825792.00 => 255 */ 0xff, /* => 352768.00 */ -/* 18874368.00 => 255 */ 0xff, /* => 352768.00 */ -/* 19922944.00 => 255 */ 0xff, /* => 352768.00 */ -/* 20971520.00 => 255 */ 0xff, /* => 352768.00 */ -/* 22020096.00 => 255 */ 0xff, /* => 352768.00 */ -/* 23068672.00 => 255 */ 0xff, /* => 352768.00 */ -/* 24117248.00 => 255 */ 0xff, /* => 352768.00 */ -/* 25165824.00 => 255 */ 0xff, /* => 352768.00 */ -/* 26214400.00 => 255 */ 0xff, /* => 352768.00 */ -/* 27262976.00 => 255 */ 0xff, /* => 352768.00 */ -/* 28311552.00 => 255 */ 0xff, /* => 352768.00 */ -/* 29360128.00 => 255 */ 0xff, /* => 352768.00 */ -/* 30408704.00 => 255 */ 0xff, /* => 352768.00 */ -/* 31457280.00 => 255 */ 0xff, /* => 352768.00 */ -/* 32505856.00 => 255 */ 0xff, /* => 352768.00 */ -/* 33554432.00 => 255 */ 0xff, /* => 352768.00 */ -/* 35651584.00 => 255 */ 0xff, /* => 352768.00 */ -/* 37748736.00 => 255 */ 0xff, /* => 352768.00 */ -/* 39845888.00 => 255 */ 0xff, /* => 352768.00 */ -/* 41943040.00 => 255 */ 0xff, /* => 352768.00 */ -/* 44040192.00 => 255 */ 0xff, /* => 352768.00 */ -/* 46137344.00 => 255 */ 0xff, /* => 352768.00 */ -/* 48234496.00 => 255 */ 0xff, /* => 352768.00 */ -/* 50331648.00 => 255 */ 0xff, /* => 352768.00 */ -/* 52428800.00 => 255 */ 0xff, /* => 352768.00 */ -/* 54525952.00 => 255 */ 0xff, /* => 352768.00 */ -/* 56623104.00 => 255 */ 0xff, /* => 352768.00 */ -/* 58720256.00 => 255 */ 0xff, /* => 352768.00 */ -/* 60817408.00 => 255 */ 0xff, /* => 352768.00 */ -/* 62914560.00 => 255 */ 0xff, /* => 352768.00 */ -/* 65011712.00 => 255 */ 0xff, /* => 352768.00 */ -/* 67108864.00 => 255 */ 0xff, /* => 352768.00 */ -/* 71303168.00 => 255 */ 0xff, /* => 352768.00 */ -/* 75497472.00 => 255 */ 0xff, /* => 352768.00 */ -/* 79691776.00 => 255 */ 0xff, /* => 352768.00 */ -/* 83886080.00 => 255 */ 0xff, /* => 352768.00 */ -/* 88080384.00 => 255 */ 0xff, /* => 352768.00 */ -/* 92274688.00 => 255 */ 0xff, /* => 352768.00 */ -/* 96468992.00 => 255 */ 0xff, /* => 352768.00 */ -/* 100663296.00 => 255 */ 0xff, /* => 352768.00 */ -/* 104857600.00 => 255 */ 0xff, /* => 352768.00 */ -/* 109051904.00 => 255 */ 0xff, /* => 352768.00 */ -/* 113246208.00 => 255 */ 0xff, /* => 352768.00 */ -/* 117440512.00 => 255 */ 0xff, /* => 352768.00 */ -/* 121634816.00 => 255 */ 0xff, /* => 352768.00 */ -/* 125829120.00 => 255 */ 0xff, /* => 352768.00 */ -/* 130023424.00 => 255 */ 0xff, /* => 352768.00 */ -/* 134217728.00 => 255 */ 0xff, /* => 352768.00 */ -/* 142606336.00 => 255 */ 0xff, /* => 352768.00 */ -/* 150994944.00 => 255 */ 0xff, /* => 352768.00 */ -/* 159383552.00 => 255 */ 0xff, /* => 352768.00 */ -/* 167772160.00 => 255 */ 0xff, /* => 352768.00 */ -/* 176160768.00 => 255 */ 0xff, /* => 352768.00 */ -/* 184549376.00 => 255 */ 0xff, /* => 352768.00 */ -/* 192937984.00 => 255 */ 0xff, /* => 352768.00 */ -/* 201326592.00 => 255 */ 0xff, /* => 352768.00 */ -/* 209715200.00 => 255 */ 0xff, /* => 352768.00 */ -/* 218103808.00 => 255 */ 0xff, /* => 352768.00 */ -/* 226492416.00 => 255 */ 0xff, /* => 352768.00 */ -/* 234881024.00 => 255 */ 0xff, /* => 352768.00 */ -/* 243269632.00 => 255 */ 0xff, /* => 352768.00 */ -/* 251658240.00 => 255 */ 0xff, /* => 352768.00 */ -/* 260046848.00 => 255 */ 0xff, /* => 352768.00 */ -/* 268435456.00 => 255 */ 0xff, /* => 352768.00 */ -/* 285212672.00 => 255 */ 0xff, /* => 352768.00 */ -/* 301989888.00 => 255 */ 0xff, /* => 352768.00 */ -/* 318767104.00 => 255 */ 0xff, /* => 352768.00 */ -/* 335544320.00 => 255 */ 0xff, /* => 352768.00 */ -/* 352321536.00 => 255 */ 0xff, /* => 352768.00 */ -/* 369098752.00 => 255 */ 0xff, /* => 352768.00 */ -/* 385875968.00 => 255 */ 0xff, /* => 352768.00 */ -/* 402653184.00 => 255 */ 0xff, /* => 352768.00 */ -/* 419430400.00 => 255 */ 0xff, /* => 352768.00 */ -/* 436207616.00 => 255 */ 0xff, /* => 352768.00 */ -/* 452984832.00 => 255 */ 0xff, /* => 352768.00 */ -/* 469762048.00 => 255 */ 0xff, /* => 352768.00 */ -/* 486539264.00 => 255 */ 0xff, /* => 352768.00 */ -/* 503316480.00 => 255 */ 0xff, /* => 352768.00 */ -/* 520093696.00 => 255 */ 0xff, /* => 352768.00 */ -/* 536870912.00 => 255 */ 0xff, /* => 352768.00 */ -/* 570425344.00 => 255 */ 0xff, /* => 352768.00 */ -/* 603979776.00 => 255 */ 0xff, /* => 352768.00 */ -/* 637534208.00 => 255 */ 0xff, /* => 352768.00 */ -/* 671088640.00 => 255 */ 0xff, /* => 352768.00 */ -/* 704643072.00 => 255 */ 0xff, /* => 352768.00 */ -/* 738197504.00 => 255 */ 0xff, /* => 352768.00 */ -/* 771751936.00 => 255 */ 0xff, /* => 352768.00 */ -/* 805306368.00 => 255 */ 0xff, /* => 352768.00 */ -/* 838860800.00 => 255 */ 0xff, /* => 352768.00 */ -/* 872415232.00 => 255 */ 0xff, /* => 352768.00 */ -/* 905969664.00 => 255 */ 0xff, /* => 352768.00 */ -/* 939524096.00 => 255 */ 0xff, /* => 352768.00 */ -/* 973078528.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1006632960.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1040187392.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1073741824.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1140850688.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1207959552.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1275068416.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1342177280.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1409286144.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1476395008.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1543503872.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1610612736.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1677721600.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1744830464.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1811939328.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1879048192.00 => 255 */ 0xff, /* => 352768.00 */ -/* 1946157056.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2013265920.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2080374784.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2147483648.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2281701376.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2415919104.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2550136832.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2684354560.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2818572288.00 => 255 */ 0xff, /* => 352768.00 */ -/* 2952790016.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3087007744.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3221225472.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3355443200.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3489660928.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3623878656.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3758096384.00 => 255 */ 0xff, /* => 352768.00 */ -/* 3892314112.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4026531840.00 => 255 */ 0xff, /* => 352768.00 */ -/* 4160749568.00 => 255 */ 0xff, /* => 352768.00 */ -}; diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h deleted file mode 100644 index 2f5f8875cbd1..000000000000 --- a/drivers/atm/iphase.h +++ /dev/null @@ -1,1452 +0,0 @@ -/****************************************************************************** - Device driver for Interphase ATM PCI adapter cards - Author: Peter Wang - Interphase Corporation - Version: 1.0 - iphase.h: This is the header file for iphase.c. -******************************************************************************* - - This software may be used and distributed according to the terms - of the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on this skeleton fall under the GPL and must retain - the authorship (implicit copyright) notice. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - Modified from an incomplete driver for Interphase 5575 1KVC 1M card which - was originally written by Monalisa Agrawal at UNH. Now this driver - supports a variety of varients of Interphase ATM PCI (i)Chip adapter - card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) - in terms of PHY type, the size of control memory and the size of - packet memory. The following are the change log and history: - - Bugfix the Mona's UBR driver. - Modify the basic memory allocation and dma logic. - Port the driver to the latest kernel from 2.0.46. - Complete the ABR logic of the driver, and added the ABR work- - around for the hardware anormalies. - Add the CBR support. - Add the flow control logic to the driver to allow rate-limit VC. - Add 4K VC support to the board with 512K control memory. - Add the support of all the variants of the Interphase ATM PCI - (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 - (25M UTP25) and x531 (DS3 and E3). - Add SMP support. - - Support and updates available at: ftp://ftp.iphase.com/pub/atm - -*******************************************************************************/ - -#ifndef IPHASE_H -#define IPHASE_H - - -/************************ IADBG DEFINE *********************************/ -/* IADebugFlag Bit Map */ -#define IF_IADBG_INIT_ADAPTER 0x00000001 // init adapter info -#define IF_IADBG_TX 0x00000002 // debug TX -#define IF_IADBG_RX 0x00000004 // debug RX -#define IF_IADBG_QUERY_INFO 0x00000008 // debug Request call -#define IF_IADBG_SHUTDOWN 0x00000010 // debug shutdown event -#define IF_IADBG_INTR 0x00000020 // debug interrupt DPC -#define IF_IADBG_TXPKT 0x00000040 // debug TX PKT -#define IF_IADBG_RXPKT 0x00000080 // debug RX PKT -#define IF_IADBG_ERR 0x00000100 // debug system error -#define IF_IADBG_EVENT 0x00000200 // debug event -#define IF_IADBG_DIS_INTR 0x00001000 // debug disable interrupt -#define IF_IADBG_EN_INTR 0x00002000 // debug enable interrupt -#define IF_IADBG_LOUD 0x00004000 // debugging info -#define IF_IADBG_VERY_LOUD 0x00008000 // excessive debugging info -#define IF_IADBG_CBR 0x00100000 // -#define IF_IADBG_UBR 0x00200000 // -#define IF_IADBG_ABR 0x00400000 // -#define IF_IADBG_DESC 0x01000000 // -#define IF_IADBG_SUNI_STAT 0x02000000 // suni statistics -#define IF_IADBG_RESET 0x04000000 - -#define IF_IADBG(f) if (IADebugFlag & (f)) - -#ifdef CONFIG_ATM_IA_DEBUG /* Debug build */ - -#define IF_LOUD(A) IF_IADBG(IF_IADBG_LOUD) { A } -#define IF_ERR(A) IF_IADBG(IF_IADBG_ERR) { A } -#define IF_VERY_LOUD(A) IF_IADBG( IF_IADBG_VERY_LOUD ) { A } - -#define IF_INIT_ADAPTER(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } -#define IF_INIT(A) IF_IADBG( IF_IADBG_INIT_ADAPTER ) { A } -#define IF_SUNI_STAT(A) IF_IADBG( IF_IADBG_SUNI_STAT ) { A } -#define IF_QUERY_INFO(A) IF_IADBG( IF_IADBG_QUERY_INFO ) { A } -#define IF_COPY_OVER(A) IF_IADBG( IF_IADBG_COPY_OVER ) { A } - -#define IF_INTR(A) IF_IADBG( IF_IADBG_INTR ) { A } -#define IF_DIS_INTR(A) IF_IADBG( IF_IADBG_DIS_INTR ) { A } -#define IF_EN_INTR(A) IF_IADBG( IF_IADBG_EN_INTR ) { A } - -#define IF_TX(A) IF_IADBG( IF_IADBG_TX ) { A } -#define IF_RX(A) IF_IADBG( IF_IADBG_RX ) { A } -#define IF_TXPKT(A) IF_IADBG( IF_IADBG_TXPKT ) { A } -#define IF_RXPKT(A) IF_IADBG( IF_IADBG_RXPKT ) { A } - -#define IF_SHUTDOWN(A) IF_IADBG(IF_IADBG_SHUTDOWN) { A } -#define IF_CBR(A) IF_IADBG( IF_IADBG_CBR ) { A } -#define IF_UBR(A) IF_IADBG( IF_IADBG_UBR ) { A } -#define IF_ABR(A) IF_IADBG( IF_IADBG_ABR ) { A } -#define IF_EVENT(A) IF_IADBG( IF_IADBG_EVENT) { A } - -#else /* free build */ -#define IF_LOUD(A) -#define IF_VERY_LOUD(A) -#define IF_INIT_ADAPTER(A) -#define IF_INIT(A) -#define IF_SUNI_STAT(A) -#define IF_PVC_CHKPKT(A) -#define IF_QUERY_INFO(A) -#define IF_COPY_OVER(A) -#define IF_HANG(A) -#define IF_INTR(A) -#define IF_DIS_INTR(A) -#define IF_EN_INTR(A) -#define IF_TX(A) -#define IF_RX(A) -#define IF_TXDEBUG(A) -#define IF_VC(A) -#define IF_ERR(A) -#define IF_CBR(A) -#define IF_UBR(A) -#define IF_ABR(A) -#define IF_SHUTDOWN(A) -#define DbgPrint(A) -#define IF_EVENT(A) -#define IF_TXPKT(A) -#define IF_RXPKT(A) -#endif /* CONFIG_ATM_IA_DEBUG */ - -#define ATM_DESC(skb) (skb->protocol) -#define IA_SKB_STATE(skb) (skb->protocol) -#define IA_DLED 1 -#define IA_TX_DONE 2 - -/* iadbg defines */ -#define IA_CMD 0x7749 -typedef struct { - int cmd; - int sub_cmd; - int len; - u32 maddr; - int status; - void __user *buf; -} IA_CMDBUF, *PIA_CMDBUF; - -/* cmds */ -#define MEMDUMP 0x01 - -/* sub_cmds */ -#define MEMDUMP_SEGREG 0x2 -#define MEMDUMP_DEV 0x1 -#define MEMDUMP_REASSREG 0x3 -#define MEMDUMP_FFL 0x4 -#define READ_REG 0x5 -#define WAKE_DBG_WAIT 0x6 - -/************************ IADBG DEFINE END ***************************/ - -#define Boolean(x) ((x) ? 1 : 0) -#define NR_VCI 1024 /* number of VCIs */ -#define NR_VCI_LD 10 /* log2(NR_VCI) */ -#define NR_VCI_4K 4096 /* number of VCIs */ -#define NR_VCI_4K_LD 12 /* log2(NR_VCI) */ -#define MEM_VALID 0xfffffff0 /* mask base address with this */ - -#ifndef PCI_VENDOR_ID_IPHASE -#define PCI_VENDOR_ID_IPHASE 0x107e -#endif -#ifndef PCI_DEVICE_ID_IPHASE_5575 -#define PCI_DEVICE_ID_IPHASE_5575 0x0008 -#endif -#define DEV_LABEL "ia" -#define PCR 207692 -#define ICR 100000 -#define MCR 0 -#define TBE 1000 -#define FRTT 1 -#define RIF 2 -#define RDF 4 -#define NRMCODE 5 /* 0 - 7 */ -#define TRMCODE 3 /* 0 - 7 */ -#define CDFCODE 6 -#define ATDFCODE 2 /* 0 - 15 */ - -/*---------------------- Packet/Cell Memory ------------------------*/ -#define TX_PACKET_RAM 0x00000 /* start of Trasnmit Packet memory - 0 */ -#define DFL_TX_BUF_SZ 10240 /* 10 K buffers */ -#define DFL_TX_BUFFERS 50 /* number of packet buffers for Tx - - descriptor 0 unused */ -#define REASS_RAM_SIZE 0x10000 /* for 64K 1K VC board */ -#define RX_PACKET_RAM 0x80000 /* start of Receive Packet memory - 512K */ -#define DFL_RX_BUF_SZ 10240 /* 10k buffers */ -#define DFL_RX_BUFFERS 50 /* number of packet buffers for Rx - - descriptor 0 unused */ - -struct cpcs_trailer -{ - u_short control; - u_short length; - u_int crc32; -}; - -struct cpcs_trailer_desc -{ - struct cpcs_trailer *cpcs; - dma_addr_t dma_addr; -}; - -struct ia_vcc -{ - int rxing; - int txing; - int NumCbrEntry; - u32 pcr; - u32 saved_tx_quota; - int flow_inc; - struct sk_buff_head txing_skb; - int ltimeout; - u8 vc_desc_cnt; - -}; - -struct abr_vc_table -{ - u_char status; - u_char rdf; - u_short air; - u_int res[3]; - u_int req_rm_cell_data1; - u_int req_rm_cell_data2; - u_int add_rm_cell_data1; - u_int add_rm_cell_data2; -}; - -/* 32 byte entries */ -struct main_vc -{ - u_short type; -#define ABR 0x8000 -#define UBR 0xc000 -#define CBR 0x0000 - /* ABR fields */ - u_short nrm; - u_short trm; - u_short rm_timestamp_hi; - u_short rm_timestamp_lo:8, - crm:8; - u_short remainder; /* ABR and UBR fields - last 10 bits*/ - u_short next_vc_sched; - u_short present_desc; /* all classes */ - u_short last_cell_slot; /* ABR and UBR */ - u_short pcr; - u_short fraction; - u_short icr; - u_short atdf; - u_short mcr; - u_short acr; - u_short unack:8, - status:8; /* all classes */ -#define UIOLI 0x80 -#define CRC_APPEND 0x40 /* for status field - CRC-32 append */ -#define ABR_STATE 0x02 - -}; - - -/* 8 byte entries */ -struct ext_vc -{ - u_short atm_hdr1; - u_short atm_hdr2; - u_short last_desc; - u_short out_of_rate_link; /* reserved for UBR and CBR */ -}; - - -#define DLE_ENTRIES 256 -#define DMA_INT_ENABLE 0x0002 /* use for both Tx and Rx */ -#define TX_DLE_PSI 0x0001 -#define DLE_TOTAL_SIZE (sizeof(struct dle)*DLE_ENTRIES) - -/* Descriptor List Entries (DLE) */ -struct dle -{ - u32 sys_pkt_addr; - u32 local_pkt_addr; - u32 bytes; - u16 prq_wr_ptr_data; - u16 mode; -}; - -struct dle_q -{ - struct dle *start; - struct dle *end; - struct dle *read; - struct dle *write; -}; - -struct free_desc_q -{ - int desc; /* Descriptor number */ - struct free_desc_q *next; -}; - -struct tx_buf_desc { - unsigned short desc_mode; - unsigned short vc_index; - unsigned short res1; /* reserved field */ - unsigned short bytes; - unsigned short buf_start_hi; - unsigned short buf_start_lo; - unsigned short res2[10]; /* reserved field */ -}; - - -struct rx_buf_desc { - unsigned short desc_mode; - unsigned short vc_index; - unsigned short vpi; - unsigned short bytes; - unsigned short buf_start_hi; - unsigned short buf_start_lo; - unsigned short dma_start_hi; - unsigned short dma_start_lo; - unsigned short crc_upper; - unsigned short crc_lower; - unsigned short res:8, timeout:8; - unsigned short res2[5]; /* reserved field */ -}; - -/*--------SAR stuff ---------------------*/ - -#define EPROM_SIZE 0x40000 /* says 64K in the docs ??? */ -#define MAC1_LEN 4 -#define MAC2_LEN 2 - -/*------------ PCI Memory Space Map, 128K SAR memory ----------------*/ -#define IPHASE5575_PCI_CONFIG_REG_BASE 0x0000 -#define IPHASE5575_BUS_CONTROL_REG_BASE 0x1000 /* offsets 0x00 - 0x3c */ -#define IPHASE5575_FRAG_CONTROL_REG_BASE 0x2000 -#define IPHASE5575_REASS_CONTROL_REG_BASE 0x3000 -#define IPHASE5575_DMA_CONTROL_REG_BASE 0x4000 -#define IPHASE5575_FRONT_END_REG_BASE IPHASE5575_DMA_CONTROL_REG_BASE -#define IPHASE5575_FRAG_CONTROL_RAM_BASE 0x10000 -#define IPHASE5575_REASS_CONTROL_RAM_BASE 0x20000 - -/*------------ Bus interface control registers -----------------*/ -#define IPHASE5575_BUS_CONTROL_REG 0x00 -#define IPHASE5575_BUS_STATUS_REG 0x01 /* actual offset 0x04 */ -#define IPHASE5575_MAC1 0x02 -#define IPHASE5575_REV 0x03 -#define IPHASE5575_MAC2 0x03 /*actual offset 0x0e-reg 0x0c*/ -#define IPHASE5575_EXT_RESET 0x04 -#define IPHASE5575_INT_RESET 0x05 /* addr 1c ?? reg 0x06 */ -#define IPHASE5575_PCI_ADDR_PAGE 0x07 /* reg 0x08, 0x09 ?? */ -#define IPHASE5575_EEPROM_ACCESS 0x0a /* actual offset 0x28 */ -#define IPHASE5575_CELL_FIFO_QUEUE_SZ 0x0b -#define IPHASE5575_CELL_FIFO_MARK_STATE 0x0c -#define IPHASE5575_CELL_FIFO_READ_PTR 0x0d -#define IPHASE5575_CELL_FIFO_WRITE_PTR 0x0e -#define IPHASE5575_CELL_FIFO_CELLS_AVL 0x0f /* actual offset 0x3c */ - -/* Bus Interface Control Register bits */ -#define CTRL_FE_RST 0x80000000 -#define CTRL_LED 0x40000000 -#define CTRL_25MBPHY 0x10000000 -#define CTRL_ENCMBMEM 0x08000000 -#define CTRL_ENOFFSEG 0x01000000 -#define CTRL_ERRMASK 0x00400000 -#define CTRL_DLETMASK 0x00100000 -#define CTRL_DLERMASK 0x00080000 -#define CTRL_FEMASK 0x00040000 -#define CTRL_SEGMASK 0x00020000 -#define CTRL_REASSMASK 0x00010000 -#define CTRL_CSPREEMPT 0x00002000 -#define CTRL_B128 0x00000200 -#define CTRL_B64 0x00000100 -#define CTRL_B48 0x00000080 -#define CTRL_B32 0x00000040 -#define CTRL_B16 0x00000020 -#define CTRL_B8 0x00000010 - -/* Bus Interface Status Register bits */ -#define STAT_CMEMSIZ 0xc0000000 -#define STAT_ADPARCK 0x20000000 -#define STAT_RESVD 0x1fffff80 -#define STAT_ERRINT 0x00000040 -#define STAT_MARKINT 0x00000020 -#define STAT_DLETINT 0x00000010 -#define STAT_DLERINT 0x00000008 -#define STAT_FEINT 0x00000004 -#define STAT_SEGINT 0x00000002 -#define STAT_REASSINT 0x00000001 - - -/*--------------- Segmentation control registers -----------------*/ -/* The segmentation registers are 16 bits access and the addresses - are defined as such so the addresses are the actual "offsets" */ -#define IDLEHEADHI 0x00 -#define IDLEHEADLO 0x01 -#define MAXRATE 0x02 -/* Values for MAXRATE register for 155Mbps and 25.6 Mbps operation */ -#define RATE155 0x64b1 // 16 bits float format -#define MAX_ATM_155 352768 // Cells/second p.118 -#define RATE25 0x5f9d - -#define STPARMS 0x03 -#define STPARMS_1K 0x008c -#define STPARMS_2K 0x0049 -#define STPARMS_4K 0x0026 -#define COMP_EN 0x4000 -#define CBR_EN 0x2000 -#define ABR_EN 0x0800 -#define UBR_EN 0x0400 - -#define ABRUBR_ARB 0x04 -#define RM_TYPE 0x05 -/*Value for RM_TYPE register for ATM Forum Traffic Mangement4.0 support*/ -#define RM_TYPE_4_0 0x0100 - -#define SEG_COMMAND_REG 0x17 -/* Values for the command register */ -#define RESET_SEG 0x0055 -#define RESET_SEG_STATE 0x00aa -#define RESET_TX_CELL_CTR 0x00cc - -#define CBR_PTR_BASE 0x20 -#define ABR_SBPTR_BASE 0x22 -#define UBR_SBPTR_BASE 0x23 -#define ABRWQ_BASE 0x26 -#define UBRWQ_BASE 0x27 -#define VCT_BASE 0x28 -#define VCTE_BASE 0x29 -#define CBR_TAB_BEG 0x2c -#define CBR_TAB_END 0x2d -#define PRQ_ST_ADR 0x30 -#define PRQ_ED_ADR 0x31 -#define PRQ_RD_PTR 0x32 -#define PRQ_WR_PTR 0x33 -#define TCQ_ST_ADR 0x34 -#define TCQ_ED_ADR 0x35 -#define TCQ_RD_PTR 0x36 -#define TCQ_WR_PTR 0x37 -#define SEG_QUEUE_BASE 0x40 -#define SEG_DESC_BASE 0x41 -#define MODE_REG_0 0x45 -#define T_ONLINE 0x0002 /* (i)chipSAR is online */ - -#define MODE_REG_1 0x46 -#define MODE_REG_1_VAL 0x0400 /*for propoer device operation*/ - -#define SEG_INTR_STATUS_REG 0x47 -#define SEG_MASK_REG 0x48 -#define TRANSMIT_DONE 0x0200 -#define TCQ_NOT_EMPTY 0x1000 /* this can be used for both the interrupt - status registers as well as the mask register */ - -#define CELL_CTR_HIGH_AUTO 0x49 -#define CELL_CTR_HIGH_NOAUTO 0xc9 -#define CELL_CTR_LO_AUTO 0x4a -#define CELL_CTR_LO_NOAUTO 0xca - -/* Diagnostic registers */ -#define NEXTDESC 0x59 -#define NEXTVC 0x5a -#define PSLOTCNT 0x5d -#define NEWDN 0x6a -#define NEWVC 0x6b -#define SBPTR 0x6c -#define ABRWQ_WRPTR 0x6f -#define ABRWQ_RDPTR 0x70 -#define UBRWQ_WRPTR 0x71 -#define UBRWQ_RDPTR 0x72 -#define CBR_VC 0x73 -#define ABR_SBVC 0x75 -#define UBR_SBVC 0x76 -#define ABRNEXTLINK 0x78 -#define UBRNEXTLINK 0x79 - - -/*----------------- Reassembly control registers ---------------------*/ -/* The reassembly registers are 16 bits access and the addresses - are defined as such so the addresses are the actual "offsets" */ -#define MODE_REG 0x00 -#define R_ONLINE 0x0002 /* (i)chip is online */ -#define IGN_RAW_FL 0x0004 - -#define PROTOCOL_ID 0x01 -#define REASS_MASK_REG 0x02 -#define REASS_INTR_STATUS_REG 0x03 -/* Interrupt Status register bits */ -#define RX_PKT_CTR_OF 0x8000 -#define RX_ERR_CTR_OF 0x4000 -#define RX_CELL_CTR_OF 0x1000 -#define RX_FREEQ_EMPT 0x0200 -#define RX_EXCPQ_FL 0x0080 -#define RX_RAWQ_FL 0x0010 -#define RX_EXCP_RCVD 0x0008 -#define RX_PKT_RCVD 0x0004 -#define RX_RAW_RCVD 0x0001 - -#define DRP_PKT_CNTR 0x04 -#define ERR_CNTR 0x05 -#define RAW_BASE_ADR 0x08 -#define CELL_CTR0 0x0c -#define CELL_CTR1 0x0d -#define REASS_COMMAND_REG 0x0f -/* Values for command register */ -#define RESET_REASS 0x0055 -#define RESET_REASS_STATE 0x00aa -#define RESET_DRP_PKT_CNTR 0x00f1 -#define RESET_ERR_CNTR 0x00f2 -#define RESET_CELL_CNTR 0x00f8 -#define RESET_REASS_ALL_REGS 0x00ff - -#define REASS_DESC_BASE 0x10 -#define VC_LKUP_BASE 0x11 -#define REASS_TABLE_BASE 0x12 -#define REASS_QUEUE_BASE 0x13 -#define PKT_TM_CNT 0x16 -#define TMOUT_RANGE 0x17 -#define INTRVL_CNTR 0x18 -#define TMOUT_INDX 0x19 -#define VP_LKUP_BASE 0x1c -#define VP_FILTER 0x1d -#define ABR_LKUP_BASE 0x1e -#define FREEQ_ST_ADR 0x24 -#define FREEQ_ED_ADR 0x25 -#define FREEQ_RD_PTR 0x26 -#define FREEQ_WR_PTR 0x27 -#define PCQ_ST_ADR 0x28 -#define PCQ_ED_ADR 0x29 -#define PCQ_RD_PTR 0x2a -#define PCQ_WR_PTR 0x2b -#define EXCP_Q_ST_ADR 0x2c -#define EXCP_Q_ED_ADR 0x2d -#define EXCP_Q_RD_PTR 0x2e -#define EXCP_Q_WR_PTR 0x2f -#define CC_FIFO_ST_ADR 0x34 -#define CC_FIFO_ED_ADR 0x35 -#define CC_FIFO_RD_PTR 0x36 -#define CC_FIFO_WR_PTR 0x37 -#define STATE_REG 0x38 -#define BUF_SIZE 0x42 -#define XTRA_RM_OFFSET 0x44 -#define DRP_PKT_CNTR_NC 0x84 -#define ERR_CNTR_NC 0x85 -#define CELL_CNTR0_NC 0x8c -#define CELL_CNTR1_NC 0x8d - -/* State Register bits */ -#define EXCPQ_EMPTY 0x0040 -#define PCQ_EMPTY 0x0010 -#define FREEQ_EMPTY 0x0004 - - -/*----------------- Front End registers/ DMA control --------------*/ -/* There is a lot of documentation error regarding these offsets ??? - eg:- 2 offsets given 800, a00 for rx counter - similarly many others - Remember again that the offsets are to be 4*register number, so - correct the #defines here -*/ -#define IPHASE5575_TX_COUNTER 0x200 /* offset - 0x800 */ -#define IPHASE5575_RX_COUNTER 0x280 /* offset - 0xa00 */ -#define IPHASE5575_TX_LIST_ADDR 0x300 /* offset - 0xc00 */ -#define IPHASE5575_RX_LIST_ADDR 0x380 /* offset - 0xe00 */ - -/*--------------------------- RAM ---------------------------*/ -/* These memory maps are actually offsets from the segmentation and reassembly RAM base addresses */ - -/* Segmentation Control Memory map */ -#define TX_DESC_BASE 0x0000 /* Buffer Decriptor Table */ -#define TX_COMP_Q 0x1000 /* Transmit Complete Queue */ -#define PKT_RDY_Q 0x1400 /* Packet Ready Queue */ -#define CBR_SCHED_TABLE 0x1800 /* CBR Table */ -#define UBR_SCHED_TABLE 0x3000 /* UBR Table */ -#define UBR_WAIT_Q 0x4000 /* UBR Wait Queue */ -#define ABR_SCHED_TABLE 0x5000 /* ABR Table */ -#define ABR_WAIT_Q 0x5800 /* ABR Wait Queue */ -#define EXT_VC_TABLE 0x6000 /* Extended VC Table */ -#define MAIN_VC_TABLE 0x8000 /* Main VC Table */ -#define SCHEDSZ 1024 /* ABR and UBR Scheduling Table size */ -#define TX_DESC_TABLE_SZ 128 /* Number of entries in the Transmit - Buffer Descriptor Table */ - -/* These are used as table offsets in Descriptor Table address generation */ -#define DESC_MODE 0x0 -#define VC_INDEX 0x1 -#define BYTE_CNT 0x3 -#define PKT_START_HI 0x4 -#define PKT_START_LO 0x5 - -/* Descriptor Mode Word Bits */ -#define EOM_EN 0x0800 -#define AAL5 0x0100 -#define APP_CRC32 0x0400 -#define CMPL_INT 0x1000 - -#define TABLE_ADDRESS(db, dn, to) \ - (((unsigned long)(db & 0x04)) << 16) | (dn << 5) | (to << 1) - -/* Reassembly Control Memory Map */ -#define RX_DESC_BASE 0x0000 /* Buffer Descriptor Table */ -#define VP_TABLE 0x5c00 /* VP Table */ -#define EXCEPTION_Q 0x5e00 /* Exception Queue */ -#define FREE_BUF_DESC_Q 0x6000 /* Free Buffer Descriptor Queue */ -#define PKT_COMP_Q 0x6800 /* Packet Complete Queue */ -#define REASS_TABLE 0x7000 /* Reassembly Table */ -#define RX_VC_TABLE 0x7800 /* VC Table */ -#define ABR_VC_TABLE 0x8000 /* ABR VC Table */ -#define RX_DESC_TABLE_SZ 736 /* Number of entries in the Receive - Buffer Descriptor Table */ -#define VP_TABLE_SZ 256 /* Number of entries in VPTable */ -#define RX_VC_TABLE_SZ 1024 /* Number of entries in VC Table */ -#define REASS_TABLE_SZ 1024 /* Number of entries in Reassembly Table */ - /* Buffer Descriptor Table */ -#define RX_ACT 0x8000 -#define RX_VPVC 0x4000 -#define RX_CNG 0x0040 -#define RX_CER 0x0008 -#define RX_PTE 0x0004 -#define RX_OFL 0x0002 -#define NUM_RX_EXCP 32 - -/* Reassembly Table */ -#define NO_AAL5_PKT 0x0000 -#define AAL5_PKT_REASSEMBLED 0x4000 -#define AAL5_PKT_TERMINATED 0x8000 -#define RAW_PKT 0xc000 -#define REASS_ABR 0x2000 - -/*-------------------- Base Registers --------------------*/ -#define REG_BASE IPHASE5575_BUS_CONTROL_REG_BASE -#define RAM_BASE IPHASE5575_FRAG_CONTROL_RAM_BASE -#define PHY_BASE IPHASE5575_FRONT_END_REG_BASE -#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE -#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE - -typedef volatile u_int ffreg_t; -typedef u_int rreg_t; - -typedef struct _ffredn_t { - ffreg_t idlehead_high; /* Idle cell header (high) */ - ffreg_t idlehead_low; /* Idle cell header (low) */ - ffreg_t maxrate; /* Maximum rate */ - ffreg_t stparms; /* Traffic Management Parameters */ - ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */ - ffreg_t rm_type; /* */ - u_int filler5[0x17 - 0x06]; - ffreg_t cmd_reg; /* Command register */ - u_int filler18[0x20 - 0x18]; - ffreg_t cbr_base; /* CBR Pointer Base */ - ffreg_t vbr_base; /* VBR Pointer Base */ - ffreg_t abr_base; /* ABR Pointer Base */ - ffreg_t ubr_base; /* UBR Pointer Base */ - u_int filler24; - ffreg_t vbrwq_base; /* VBR Wait Queue Base */ - ffreg_t abrwq_base; /* ABR Wait Queue Base */ - ffreg_t ubrwq_base; /* UBR Wait Queue Base */ - ffreg_t vct_base; /* Main VC Table Base */ - ffreg_t vcte_base; /* Extended Main VC Table Base */ - u_int filler2a[0x2C - 0x2A]; - ffreg_t cbr_tab_beg; /* CBR Table Begin */ - ffreg_t cbr_tab_end; /* CBR Table End */ - ffreg_t cbr_pointer; /* CBR Pointer */ - u_int filler2f[0x30 - 0x2F]; - ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */ - ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */ - ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */ - ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */ - ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/ - ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */ - ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */ - ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/ - u_int filler38[0x40 - 0x38]; - ffreg_t queue_base; /* Base address for PRQ and TCQ */ - ffreg_t desc_base; /* Base address of descriptor table */ - u_int filler42[0x45 - 0x42]; - ffreg_t mode_reg_0; /* Mode register 0 */ - ffreg_t mode_reg_1; /* Mode register 1 */ - ffreg_t intr_status_reg;/* Interrupt Status register */ - ffreg_t mask_reg; /* Mask Register */ - ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */ - ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */ - ffreg_t state_reg; /* Status register */ - u_int filler4c[0x58 - 0x4c]; - ffreg_t curr_desc_num; /* Contains the current descriptor num */ - ffreg_t next_desc; /* Next descriptor */ - ffreg_t next_vc; /* Next VC */ - u_int filler5b[0x5d - 0x5b]; - ffreg_t present_slot_cnt;/* Present slot count */ - u_int filler5e[0x6a - 0x5e]; - ffreg_t new_desc_num; /* New descriptor number */ - ffreg_t new_vc; /* New VC */ - ffreg_t sched_tbl_ptr; /* Schedule table pointer */ - ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */ - ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */ - ffreg_t abrwq_wptr; /* ABR wait queue write pointer */ - ffreg_t abrwq_rptr; /* ABR wait queue read pointer */ - ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */ - ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */ - ffreg_t cbr_vc; /* CBR VC */ - ffreg_t vbr_sb_vc; /* VBR SB VC */ - ffreg_t abr_sb_vc; /* ABR SB VC */ - ffreg_t ubr_sb_vc; /* UBR SB VC */ - ffreg_t vbr_next_link; /* VBR next link */ - ffreg_t abr_next_link; /* ABR next link */ - ffreg_t ubr_next_link; /* UBR next link */ - u_int filler7a[0x7c-0x7a]; - ffreg_t out_rate_head; /* Out of rate head */ - u_int filler7d[0xca-0x7d]; /* pad out to full address space */ - ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */ - ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */ - u_int fillercc[0x100-0xcc]; /* pad out to full address space */ -} ffredn_t; - -typedef struct _rfredn_t { - rreg_t mode_reg_0; /* Mode register 0 */ - rreg_t protocol_id; /* Protocol ID */ - rreg_t mask_reg; /* Mask Register */ - rreg_t intr_status_reg;/* Interrupt status register */ - rreg_t drp_pkt_cntr; /* Dropped packet cntr (clear on read) */ - rreg_t err_cntr; /* Error Counter (cleared on read) */ - u_int filler6[0x08 - 0x06]; - rreg_t raw_base_adr; /* Base addr for raw cell Q */ - u_int filler2[0x0c - 0x09]; - rreg_t cell_ctr0; /* Cell Counter 0 (cleared when read) */ - rreg_t cell_ctr1; /* Cell Counter 1 (cleared when read) */ - u_int filler3[0x0f - 0x0e]; - rreg_t cmd_reg; /* Command register */ - rreg_t desc_base; /* Base address for description table */ - rreg_t vc_lkup_base; /* Base address for VC lookup table */ - rreg_t reass_base; /* Base address for reassembler table */ - rreg_t queue_base; /* Base address for Communication queue */ - u_int filler14[0x16 - 0x14]; - rreg_t pkt_tm_cnt; /* Packet Timeout and count register */ - rreg_t tmout_range; /* Range of reassembley IDs for timeout */ - rreg_t intrvl_cntr; /* Packet aging interval counter */ - rreg_t tmout_indx; /* index of pkt being tested for aging */ - u_int filler1a[0x1c - 0x1a]; - rreg_t vp_lkup_base; /* Base address for VP lookup table */ - rreg_t vp_filter; /* VP filter register */ - rreg_t abr_lkup_base; /* Base address of ABR VC Table */ - u_int filler1f[0x24 - 0x1f]; - rreg_t fdq_st_adr; /* Free desc queue start address */ - rreg_t fdq_ed_adr; /* Free desc queue end address */ - rreg_t fdq_rd_ptr; /* Free desc queue read pointer */ - rreg_t fdq_wr_ptr; /* Free desc queue write pointer */ - rreg_t pcq_st_adr; /* Packet Complete queue start address */ - rreg_t pcq_ed_adr; /* Packet Complete queue end address */ - rreg_t pcq_rd_ptr; /* Packet Complete queue read pointer */ - rreg_t pcq_wr_ptr; /* Packet Complete queue write pointer */ - rreg_t excp_st_adr; /* Exception queue start address */ - rreg_t excp_ed_adr; /* Exception queue end address */ - rreg_t excp_rd_ptr; /* Exception queue read pointer */ - rreg_t excp_wr_ptr; /* Exception queue write pointer */ - u_int filler30[0x34 - 0x30]; - rreg_t raw_st_adr; /* Raw Cell start address */ - rreg_t raw_ed_adr; /* Raw Cell end address */ - rreg_t raw_rd_ptr; /* Raw Cell read pointer */ - rreg_t raw_wr_ptr; /* Raw Cell write pointer */ - rreg_t state_reg; /* State Register */ - u_int filler39[0x42 - 0x39]; - rreg_t buf_size; /* Buffer size */ - u_int filler43; - rreg_t xtra_rm_offset; /* Offset of the additional turnaround RM */ - u_int filler45[0x84 - 0x45]; - rreg_t drp_pkt_cntr_nc;/* Dropped Packet cntr, Not clear on rd */ - rreg_t err_cntr_nc; /* Error Counter, Not clear on read */ - u_int filler86[0x8c - 0x86]; - rreg_t cell_ctr0_nc; /* Cell Counter 0, Not clear on read */ - rreg_t cell_ctr1_nc; /* Cell Counter 1, Not clear on read */ - u_int filler8e[0x100-0x8e]; /* pad out to full address space */ -} rfredn_t; - -typedef struct { - /* Atlantic */ - ffredn_t ffredn; /* F FRED */ - rfredn_t rfredn; /* R FRED */ -} ia_regs_t; - -typedef struct { - u_short f_vc_type; /* VC type */ - u_short f_nrm; /* Nrm */ - u_short f_nrmexp; /* Nrm Exp */ - u_short reserved6; /* */ - u_short f_crm; /* Crm */ - u_short reserved10; /* Reserved */ - u_short reserved12; /* Reserved */ - u_short reserved14; /* Reserved */ - u_short last_cell_slot; /* last_cell_slot_count */ - u_short f_pcr; /* Peak Cell Rate */ - u_short fraction; /* fraction */ - u_short f_icr; /* Initial Cell Rate */ - u_short f_cdf; /* */ - u_short f_mcr; /* Minimum Cell Rate */ - u_short f_acr; /* Allowed Cell Rate */ - u_short f_status; /* */ -} f_vc_abr_entry; - -typedef struct { - u_short r_status_rdf; /* status + RDF */ - u_short r_air; /* AIR */ - u_short reserved4[14]; /* Reserved */ -} r_vc_abr_entry; - -#define MRM 3 - -typedef struct srv_cls_param { - u32 class_type; /* CBR/VBR/ABR/UBR; use the enum above */ - u32 pcr; /* Peak Cell Rate (24-bit) */ - /* VBR parameters */ - u32 scr; /* sustainable cell rate */ - u32 max_burst_size; /* ?? cell rate or data rate */ - - /* ABR only UNI 4.0 Parameters */ - u32 mcr; /* Min Cell Rate (24-bit) */ - u32 icr; /* Initial Cell Rate (24-bit) */ - u32 tbe; /* Transient Buffer Exposure (24-bit) */ - u32 frtt; /* Fixed Round Trip Time (24-bit) */ - -#if 0 /* Additional Parameters of TM 4.0 */ -bits 31 30 29 28 27-25 24-22 21-19 18-9 ------------------------------------------------------------------------------ -| NRM present | TRM prsnt | CDF prsnt | ADTF prsnt | NRM | TRM | CDF | ADTF | ------------------------------------------------------------------------------ -#endif /* 0 */ - - u8 nrm; /* Max # of Cells for each forward RM - cell (3-bit) */ - u8 trm; /* Time between forward RM cells (3-bit) */ - u16 adtf; /* ACR Decrease Time Factor (10-bit) */ - u8 cdf; /* Cutoff Decrease Factor (3-bit) */ - u8 rif; /* Rate Increment Factor (4-bit) */ - u8 rdf; /* Rate Decrease Factor (4-bit) */ - u8 reserved; /* 8 bits to keep structure word aligned */ -} srv_cls_param_t; - -struct testTable_t { - u16 lastTime; - u16 fract; - u8 vc_status; -}; - -typedef struct { - u16 vci; - u16 error; -} RX_ERROR_Q; - -typedef struct { - u8 active: 1; - u8 abr: 1; - u8 ubr: 1; - u8 cnt: 5; -#define VC_ACTIVE 0x01 -#define VC_ABR 0x02 -#define VC_UBR 0x04 -} vcstatus_t; - -struct ia_rfL_t { - u32 fdq_st; /* Free desc queue start address */ - u32 fdq_ed; /* Free desc queue end address */ - u32 fdq_rd; /* Free desc queue read pointer */ - u32 fdq_wr; /* Free desc queue write pointer */ - u32 pcq_st; /* Packet Complete queue start address */ - u32 pcq_ed; /* Packet Complete queue end address */ - u32 pcq_rd; /* Packet Complete queue read pointer */ - u32 pcq_wr; /* Packet Complete queue write pointer */ -}; - -struct ia_ffL_t { - u32 prq_st; /* Packet Ready Queue Start Address */ - u32 prq_ed; /* Packet Ready Queue End Address */ - u32 prq_wr; /* Packet Ready Queue write pointer */ - u32 tcq_st; /* Transmit Complete Queue Start Address*/ - u32 tcq_ed; /* Transmit Complete Queue End Address */ - u32 tcq_rd; /* Transmit Complete Queue read pointer */ -}; - -struct desc_tbl_t { - u32 timestamp; - struct ia_vcc *iavcc; - struct sk_buff *txskb; -}; - -typedef struct ia_rtn_q { - struct desc_tbl_t data; - struct ia_rtn_q *next, *tail; -} IARTN_Q; - -#define SUNI_LOSV 0x04 -enum ia_suni { - SUNI_MASTER_RESET = 0x000, /* SUNI Master Reset and Identity */ - SUNI_MASTER_CONFIG = 0x004, /* SUNI Master Configuration */ - SUNI_MASTER_INTR_STAT = 0x008, /* SUNI Master Interrupt Status */ - SUNI_RESERVED1 = 0x00c, /* Reserved */ - SUNI_MASTER_CLK_MONITOR = 0x010, /* SUNI Master Clock Monitor */ - SUNI_MASTER_CONTROL = 0x014, /* SUNI Master Clock Monitor */ - /* Reserved (10) */ - SUNI_RSOP_CONTROL = 0x040, /* RSOP Control/Interrupt Enable */ - SUNI_RSOP_STATUS = 0x044, /* RSOP Status/Interrupt States */ - SUNI_RSOP_SECTION_BIP8L = 0x048, /* RSOP Section BIP-8 LSB */ - SUNI_RSOP_SECTION_BIP8M = 0x04c, /* RSOP Section BIP-8 MSB */ - - SUNI_TSOP_CONTROL = 0x050, /* TSOP Control */ - SUNI_TSOP_DIAG = 0x054, /* TSOP Disgnostics */ - /* Reserved (2) */ - SUNI_RLOP_CS = 0x060, /* RLOP Control/Status */ - SUNI_RLOP_INTR = 0x064, /* RLOP Interrupt Enable/Status */ - SUNI_RLOP_LINE_BIP24L = 0x068, /* RLOP Line BIP-24 LSB */ - SUNI_RLOP_LINE_BIP24 = 0x06c, /* RLOP Line BIP-24 */ - SUNI_RLOP_LINE_BIP24M = 0x070, /* RLOP Line BIP-24 MSB */ - SUNI_RLOP_LINE_FEBEL = 0x074, /* RLOP Line FEBE LSB */ - SUNI_RLOP_LINE_FEBE = 0x078, /* RLOP Line FEBE */ - SUNI_RLOP_LINE_FEBEM = 0x07c, /* RLOP Line FEBE MSB */ - - SUNI_TLOP_CONTROL = 0x080, /* TLOP Control */ - SUNI_TLOP_DISG = 0x084, /* TLOP Disgnostics */ - /* Reserved (14) */ - SUNI_RPOP_CS = 0x0c0, /* RPOP Status/Control */ - SUNI_RPOP_INTR = 0x0c4, /* RPOP Interrupt/Status */ - SUNI_RPOP_RESERVED = 0x0c8, /* RPOP Reserved */ - SUNI_RPOP_INTR_ENA = 0x0cc, /* RPOP Interrupt Enable */ - /* Reserved (3) */ - SUNI_RPOP_PATH_SIG = 0x0dc, /* RPOP Path Signal Label */ - SUNI_RPOP_BIP8L = 0x0e0, /* RPOP Path BIP-8 LSB */ - SUNI_RPOP_BIP8M = 0x0e4, /* RPOP Path BIP-8 MSB */ - SUNI_RPOP_FEBEL = 0x0e8, /* RPOP Path FEBE LSB */ - SUNI_RPOP_FEBEM = 0x0ec, /* RPOP Path FEBE MSB */ - /* Reserved (4) */ - SUNI_TPOP_CNTRL_DAIG = 0x100, /* TPOP Control/Disgnostics */ - SUNI_TPOP_POINTER_CTRL = 0x104, /* TPOP Pointer Control */ - SUNI_TPOP_SOURCER_CTRL = 0x108, /* TPOP Source Control */ - /* Reserved (2) */ - SUNI_TPOP_ARB_PRTL = 0x114, /* TPOP Arbitrary Pointer LSB */ - SUNI_TPOP_ARB_PRTM = 0x118, /* TPOP Arbitrary Pointer MSB */ - SUNI_TPOP_RESERVED2 = 0x11c, /* TPOP Reserved */ - SUNI_TPOP_PATH_SIG = 0x120, /* TPOP Path Signal Lable */ - SUNI_TPOP_PATH_STATUS = 0x124, /* TPOP Path Status */ - /* Reserved (6) */ - SUNI_RACP_CS = 0x140, /* RACP Control/Status */ - SUNI_RACP_INTR = 0x144, /* RACP Interrupt Enable/Status */ - SUNI_RACP_HDR_PATTERN = 0x148, /* RACP Match Header Pattern */ - SUNI_RACP_HDR_MASK = 0x14c, /* RACP Match Header Mask */ - SUNI_RACP_CORR_HCS = 0x150, /* RACP Correctable HCS Error Count */ - SUNI_RACP_UNCORR_HCS = 0x154, /* RACP Uncorrectable HCS Err Count */ - /* Reserved (10) */ - SUNI_TACP_CONTROL = 0x180, /* TACP Control */ - SUNI_TACP_IDLE_HDR_PAT = 0x184, /* TACP Idle Cell Header Pattern */ - SUNI_TACP_IDLE_PAY_PAY = 0x188, /* TACP Idle Cell Payld Octet Patrn */ - /* Reserved (5) */ - /* Reserved (24) */ - /* FIXME: unused but name conflicts. - * SUNI_MASTER_TEST = 0x200, SUNI Master Test */ - SUNI_RESERVED_TEST = 0x204 /* SUNI Reserved for Test */ -}; - -typedef struct _SUNI_STATS_ -{ - u32 valid; // 1 = oc3 PHY card - u32 carrier_detect; // GPIN input - // RSOP: receive section overhead processor - u16 rsop_oof_state; // 1 = out of frame - u16 rsop_lof_state; // 1 = loss of frame - u16 rsop_los_state; // 1 = loss of signal - u32 rsop_los_count; // loss of signal count - u32 rsop_bse_count; // section BIP-8 error count - // RLOP: receive line overhead processor - u16 rlop_ferf_state; // 1 = far end receive failure - u16 rlop_lais_state; // 1 = line AIS - u32 rlop_lbe_count; // BIP-24 count - u32 rlop_febe_count; // FEBE count; - // RPOP: receive path overhead processor - u16 rpop_lop_state; // 1 = LOP - u16 rpop_pais_state; // 1 = path AIS - u16 rpop_pyel_state; // 1 = path yellow alert - u32 rpop_bip_count; // path BIP-8 error count - u32 rpop_febe_count; // path FEBE error count - u16 rpop_psig; // path signal label value - // RACP: receive ATM cell processor - u16 racp_hp_state; // hunt/presync state - u32 racp_fu_count; // FIFO underrun count - u32 racp_fo_count; // FIFO overrun count - u32 racp_chcs_count; // correctable HCS error count - u32 racp_uchcs_count; // uncorrectable HCS error count -} IA_SUNI_STATS; - -typedef struct iadev_priv { - /*-----base pointers into (i)chipSAR+ address space */ - u32 __iomem *phy; /* Base pointer into phy (SUNI). */ - u32 __iomem *dma; /* Base pointer into DMA control registers. */ - u32 __iomem *reg; /* Base pointer to SAR registers. */ - u32 __iomem *seg_reg; /* base pointer to segmentation engine - internal registers */ - u32 __iomem *reass_reg; /* base pointer to reassemble engine - internal registers */ - u32 __iomem *ram; /* base pointer to SAR RAM */ - void __iomem *seg_ram; - void __iomem *reass_ram; - struct dle_q tx_dle_q; - struct free_desc_q *tx_free_desc_qhead; - struct sk_buff_head tx_dma_q, tx_backlog; - spinlock_t tx_lock; - IARTN_Q tx_return_q; - u32 close_pending; - wait_queue_head_t close_wait; - wait_queue_head_t timeout_wait; - struct cpcs_trailer_desc *tx_buf; - u16 num_tx_desc, tx_buf_sz, rate_limit; - u32 tx_cell_cnt, tx_pkt_cnt; - void __iomem *MAIN_VC_TABLE_ADDR, *EXT_VC_TABLE_ADDR, *ABR_SCHED_TABLE_ADDR; - struct dle_q rx_dle_q; - struct free_desc_q *rx_free_desc_qhead; - struct sk_buff_head rx_dma_q; - spinlock_t rx_lock; - struct atm_vcc **rx_open; /* list of all open VCs */ - u16 num_rx_desc, rx_buf_sz, rxing; - u32 rx_pkt_ram, rx_tmp_cnt; - unsigned long rx_tmp_jif; - void __iomem *RX_DESC_BASE_ADDR; - u32 drop_rxpkt, drop_rxcell, rx_cell_cnt, rx_pkt_cnt; - struct atm_dev *next_board; /* other iphase devices */ - struct pci_dev *pci; - int mem; - unsigned int real_base; /* real and virtual base address */ - void __iomem *base; - unsigned int pci_map_size; /*pci map size of board */ - unsigned char irq; - unsigned char bus; - unsigned char dev_fn; - u_short phy_type; - u_short num_vc, memSize, memType; - struct ia_ffL_t ffL; - struct ia_rfL_t rfL; - /* Suni stat */ - // IA_SUNI_STATS suni_stats; - unsigned char carrier_detect; - /* CBR related */ - // transmit DMA & Receive - unsigned int tx_dma_cnt; // number of elements on dma queue - unsigned int rx_dma_cnt; // number of elements on rx dma queue - unsigned int NumEnabledCBR; // number of CBR VCI's enabled. CBR - // receive MARK for Cell FIFO - unsigned int rx_mark_cnt; // number of elements on mark queue - unsigned int CbrTotEntries; // Total CBR Entries in Scheduling Table. - unsigned int CbrRemEntries; // Remaining CBR Entries in Scheduling Table. - unsigned int CbrEntryPt; // CBR Sched Table Entry Point. - unsigned int Granularity; // CBR Granularity given Table Size. - /* ABR related */ - unsigned int sum_mcr, sum_cbr, LineRate; - unsigned int n_abr; - struct desc_tbl_t *desc_tbl; - u_short host_tcq_wr; - struct testTable_t **testTable; - dma_addr_t tx_dle_dma; - dma_addr_t rx_dle_dma; -} IADEV; - - -#define INPH_IA_DEV(d) ((IADEV *) (d)->dev_data) -#define INPH_IA_VCC(v) ((struct ia_vcc *) (v)->dev_data) - -/******************* IDT77105 25MB/s PHY DEFINE *****************************/ -enum ia_mb25 { - MB25_MASTER_CTRL = 0x00, /* Master control */ - MB25_INTR_STATUS = 0x04, /* Interrupt status */ - MB25_DIAG_CONTROL = 0x08, /* Diagnostic control */ - MB25_LED_HEC = 0x0c, /* LED driver and HEC status/control */ - MB25_LOW_BYTE_COUNTER = 0x10, - MB25_HIGH_BYTE_COUNTER = 0x14 -}; - -/* - * Master Control - */ -#define MB25_MC_UPLO 0x80 /* UPLO */ -#define MB25_MC_DREC 0x40 /* Discard receive cell errors */ -#define MB25_MC_ECEIO 0x20 /* Enable Cell Error Interrupts Only */ -#define MB25_MC_TDPC 0x10 /* Transmit data parity check */ -#define MB25_MC_DRIC 0x08 /* Discard receive idle cells */ -#define MB25_MC_HALTTX 0x04 /* Halt Tx */ -#define MB25_MC_UMS 0x02 /* UTOPIA mode select */ -#define MB25_MC_ENABLED 0x01 /* Enable interrupt */ - -/* - * Interrupt Status - */ -#define MB25_IS_GSB 0x40 /* GOOD Symbol Bit */ -#define MB25_IS_HECECR 0x20 /* HEC error cell received */ -#define MB25_IS_SCR 0x10 /* "Short Cell" Received */ -#define MB25_IS_TPE 0x08 /* Trnamsit Parity Error */ -#define MB25_IS_RSCC 0x04 /* Receive Signal Condition change */ -#define MB25_IS_RCSE 0x02 /* Received Cell Symbol Error */ -#define MB25_IS_RFIFOO 0x01 /* Received FIFO Overrun */ - -/* - * Diagnostic Control - */ -#define MB25_DC_FTXCD 0x80 /* Force TxClav deassert */ -#define MB25_DC_RXCOS 0x40 /* RxClav operation select */ -#define MB25_DC_ECEIO 0x20 /* Single/Multi-PHY config select */ -#define MB25_DC_RLFLUSH 0x10 /* Clear receive FIFO */ -#define MB25_DC_IXPE 0x08 /* Insert xmit payload error */ -#define MB25_DC_IXHECE 0x04 /* Insert Xmit HEC Error */ -#define MB25_DC_LB_MASK 0x03 /* Loopback control mask */ - -#define MB25_DC_LL 0x03 /* Line Loopback */ -#define MB25_DC_PL 0x02 /* PHY Loopback */ -#define MB25_DC_NM 0x00 - -#define FE_MASK 0x00F0 -#define FE_MULTI_MODE 0x0000 -#define FE_SINGLE_MODE 0x0010 -#define FE_UTP_OPTION 0x0020 -#define FE_25MBIT_PHY 0x0040 -#define FE_DS3_PHY 0x0080 /* DS3 */ -#define FE_E3_PHY 0x0090 /* E3 */ - -/*********************** SUNI_PM7345 PHY DEFINE HERE *********************/ -enum suni_pm7345 { - SUNI_CONFIG = 0x000, /* SUNI Configuration */ - SUNI_INTR_ENBL = 0x004, /* SUNI Interrupt Enable */ - SUNI_INTR_STAT = 0x008, /* SUNI Interrupt Status */ - SUNI_CONTROL = 0x00c, /* SUNI Control */ - SUNI_ID_RESET = 0x010, /* SUNI Reset and Identity */ - SUNI_DATA_LINK_CTRL = 0x014, - SUNI_RBOC_CONF_INTR_ENBL = 0x018, - SUNI_RBOC_STAT = 0x01c, - SUNI_DS3_FRM_CFG = 0x020, - SUNI_DS3_FRM_INTR_ENBL = 0x024, - SUNI_DS3_FRM_INTR_STAT = 0x028, - SUNI_DS3_FRM_STAT = 0x02c, - SUNI_RFDL_CFG = 0x030, - SUNI_RFDL_ENBL_STAT = 0x034, - SUNI_RFDL_STAT = 0x038, - SUNI_RFDL_DATA = 0x03c, - SUNI_PMON_CHNG = 0x040, - SUNI_PMON_INTR_ENBL_STAT = 0x044, - /* SUNI_RESERVED1 (0x13 - 0x11) */ - SUNI_PMON_LCV_EVT_CNT_LSB = 0x050, - SUNI_PMON_LCV_EVT_CNT_MSB = 0x054, - SUNI_PMON_FBE_EVT_CNT_LSB = 0x058, - SUNI_PMON_FBE_EVT_CNT_MSB = 0x05c, - SUNI_PMON_SEZ_DET_CNT_LSB = 0x060, - SUNI_PMON_SEZ_DET_CNT_MSB = 0x064, - SUNI_PMON_PE_EVT_CNT_LSB = 0x068, - SUNI_PMON_PE_EVT_CNT_MSB = 0x06c, - SUNI_PMON_PPE_EVT_CNT_LSB = 0x070, - SUNI_PMON_PPE_EVT_CNT_MSB = 0x074, - SUNI_PMON_FEBE_EVT_CNT_LSB = 0x078, - SUNI_PMON_FEBE_EVT_CNT_MSB = 0x07c, - SUNI_DS3_TRAN_CFG = 0x080, - SUNI_DS3_TRAN_DIAG = 0x084, - /* SUNI_RESERVED2 (0x23 - 0x21) */ - SUNI_XFDL_CFG = 0x090, - SUNI_XFDL_INTR_ST = 0x094, - SUNI_XFDL_XMIT_DATA = 0x098, - SUNI_XBOC_CODE = 0x09c, - SUNI_SPLR_CFG = 0x0a0, - SUNI_SPLR_INTR_EN = 0x0a4, - SUNI_SPLR_INTR_ST = 0x0a8, - SUNI_SPLR_STATUS = 0x0ac, - SUNI_SPLT_CFG = 0x0b0, - SUNI_SPLT_CNTL = 0x0b4, - SUNI_SPLT_DIAG_G1 = 0x0b8, - SUNI_SPLT_F1 = 0x0bc, - SUNI_CPPM_LOC_METERS = 0x0c0, - SUNI_CPPM_CHG_OF_CPPM_PERF_METR = 0x0c4, - SUNI_CPPM_B1_ERR_CNT_LSB = 0x0c8, - SUNI_CPPM_B1_ERR_CNT_MSB = 0x0cc, - SUNI_CPPM_FRAMING_ERR_CNT_LSB = 0x0d0, - SUNI_CPPM_FRAMING_ERR_CNT_MSB = 0x0d4, - SUNI_CPPM_FEBE_CNT_LSB = 0x0d8, - SUNI_CPPM_FEBE_CNT_MSB = 0x0dc, - SUNI_CPPM_HCS_ERR_CNT_LSB = 0x0e0, - SUNI_CPPM_HCS_ERR_CNT_MSB = 0x0e4, - SUNI_CPPM_IDLE_UN_CELL_CNT_LSB = 0x0e8, - SUNI_CPPM_IDLE_UN_CELL_CNT_MSB = 0x0ec, - SUNI_CPPM_RCV_CELL_CNT_LSB = 0x0f0, - SUNI_CPPM_RCV_CELL_CNT_MSB = 0x0f4, - SUNI_CPPM_XMIT_CELL_CNT_LSB = 0x0f8, - SUNI_CPPM_XMIT_CELL_CNT_MSB = 0x0fc, - SUNI_RXCP_CTRL = 0x100, - SUNI_RXCP_FCTRL = 0x104, - SUNI_RXCP_INTR_EN_STS = 0x108, - SUNI_RXCP_IDLE_PAT_H1 = 0x10c, - SUNI_RXCP_IDLE_PAT_H2 = 0x110, - SUNI_RXCP_IDLE_PAT_H3 = 0x114, - SUNI_RXCP_IDLE_PAT_H4 = 0x118, - SUNI_RXCP_IDLE_MASK_H1 = 0x11c, - SUNI_RXCP_IDLE_MASK_H2 = 0x120, - SUNI_RXCP_IDLE_MASK_H3 = 0x124, - SUNI_RXCP_IDLE_MASK_H4 = 0x128, - SUNI_RXCP_CELL_PAT_H1 = 0x12c, - SUNI_RXCP_CELL_PAT_H2 = 0x130, - SUNI_RXCP_CELL_PAT_H3 = 0x134, - SUNI_RXCP_CELL_PAT_H4 = 0x138, - SUNI_RXCP_CELL_MASK_H1 = 0x13c, - SUNI_RXCP_CELL_MASK_H2 = 0x140, - SUNI_RXCP_CELL_MASK_H3 = 0x144, - SUNI_RXCP_CELL_MASK_H4 = 0x148, - SUNI_RXCP_HCS_CS = 0x14c, - SUNI_RXCP_LCD_CNT_THRESHOLD = 0x150, - /* SUNI_RESERVED3 (0x57 - 0x54) */ - SUNI_TXCP_CTRL = 0x160, - SUNI_TXCP_INTR_EN_STS = 0x164, - SUNI_TXCP_IDLE_PAT_H1 = 0x168, - SUNI_TXCP_IDLE_PAT_H2 = 0x16c, - SUNI_TXCP_IDLE_PAT_H3 = 0x170, - SUNI_TXCP_IDLE_PAT_H4 = 0x174, - SUNI_TXCP_IDLE_PAT_H5 = 0x178, - SUNI_TXCP_IDLE_PAYLOAD = 0x17c, - SUNI_E3_FRM_FRAM_OPTIONS = 0x180, - SUNI_E3_FRM_MAINT_OPTIONS = 0x184, - SUNI_E3_FRM_FRAM_INTR_ENBL = 0x188, - SUNI_E3_FRM_FRAM_INTR_IND_STAT = 0x18c, - SUNI_E3_FRM_MAINT_INTR_ENBL = 0x190, - SUNI_E3_FRM_MAINT_INTR_IND = 0x194, - SUNI_E3_FRM_MAINT_STAT = 0x198, - SUNI_RESERVED4 = 0x19c, - SUNI_E3_TRAN_FRAM_OPTIONS = 0x1a0, - SUNI_E3_TRAN_STAT_DIAG_OPTIONS = 0x1a4, - SUNI_E3_TRAN_BIP_8_ERR_MASK = 0x1a8, - SUNI_E3_TRAN_MAINT_ADAPT_OPTS = 0x1ac, - SUNI_TTB_CTRL = 0x1b0, - SUNI_TTB_TRAIL_TRACE_ID_STAT = 0x1b4, - SUNI_TTB_IND_ADDR = 0x1b8, - SUNI_TTB_IND_DATA = 0x1bc, - SUNI_TTB_EXP_PAYLOAD_TYPE = 0x1c0, - SUNI_TTB_PAYLOAD_TYPE_CTRL_STAT = 0x1c4, - /* SUNI_PAD5 (0x7f - 0x71) */ - SUNI_MASTER_TEST = 0x200, - /* SUNI_PAD6 (0xff - 0x80) */ -}; - -#define SUNI_PM7345_T suni_pm7345_t -#define SUNI_PM7345 0x20 /* Suni chip type */ -#define SUNI_PM5346 0x30 /* Suni chip type */ -/* - * SUNI_PM7345 Configuration - */ -#define SUNI_PM7345_CLB 0x01 /* Cell loopback */ -#define SUNI_PM7345_PLB 0x02 /* Payload loopback */ -#define SUNI_PM7345_DLB 0x04 /* Diagnostic loopback */ -#define SUNI_PM7345_LLB 0x80 /* Line loopback */ -#define SUNI_PM7345_E3ENBL 0x40 /* E3 enable bit */ -#define SUNI_PM7345_LOOPT 0x10 /* LOOPT enable bit */ -#define SUNI_PM7345_FIFOBP 0x20 /* FIFO bypass */ -#define SUNI_PM7345_FRMRBP 0x08 /* Framer bypass */ -/* - * DS3 FRMR Interrupt Enable - */ -#define SUNI_DS3_COFAE 0x80 /* Enable change of frame align */ -#define SUNI_DS3_REDE 0x40 /* Enable DS3 RED state intr */ -#define SUNI_DS3_CBITE 0x20 /* Enable Appl ID channel intr */ -#define SUNI_DS3_FERFE 0x10 /* Enable Far End Receive Failure intr*/ -#define SUNI_DS3_IDLE 0x08 /* Enable Idle signal intr */ -#define SUNI_DS3_AISE 0x04 /* Enable Alarm Indication signal intr*/ -#define SUNI_DS3_OOFE 0x02 /* Enable Out of frame intr */ -#define SUNI_DS3_LOSE 0x01 /* Enable Loss of signal intr */ - -/* - * DS3 FRMR Status - */ -#define SUNI_DS3_ACE 0x80 /* Additional Configuration Reg */ -#define SUNI_DS3_REDV 0x40 /* DS3 RED state */ -#define SUNI_DS3_CBITV 0x20 /* Application ID channel state */ -#define SUNI_DS3_FERFV 0x10 /* Far End Receive Failure state*/ -#define SUNI_DS3_IDLV 0x08 /* Idle signal state */ -#define SUNI_DS3_AISV 0x04 /* Alarm Indication signal state*/ -#define SUNI_DS3_OOFV 0x02 /* Out of frame state */ -#define SUNI_DS3_LOSV 0x01 /* Loss of signal state */ - -/* - * E3 FRMR Interrupt/Status - */ -#define SUNI_E3_CZDI 0x40 /* Consecutive Zeros indicator */ -#define SUNI_E3_LOSI 0x20 /* Loss of signal intr status */ -#define SUNI_E3_LCVI 0x10 /* Line code violation intr */ -#define SUNI_E3_COFAI 0x08 /* Change of frame align intr */ -#define SUNI_E3_OOFI 0x04 /* Out of frame intr status */ -#define SUNI_E3_LOS 0x02 /* Loss of signal state */ -#define SUNI_E3_OOF 0x01 /* Out of frame state */ - -/* - * E3 FRMR Maintenance Status - */ -#define SUNI_E3_AISD 0x80 /* Alarm Indication signal state*/ -#define SUNI_E3_FERF_RAI 0x40 /* FERF/RAI indicator */ -#define SUNI_E3_FEBE 0x20 /* Far End Block Error indicator*/ - -/* - * RXCP Control/Status - */ -#define SUNI_DS3_HCSPASS 0x80 /* Pass cell with HEC errors */ -#define SUNI_DS3_HCSDQDB 0x40 /* Control octets in HCS calc */ -#define SUNI_DS3_HCSADD 0x20 /* Add coset poly */ -#define SUNI_DS3_HCK 0x10 /* Control FIFO data path integ chk*/ -#define SUNI_DS3_BLOCK 0x08 /* Enable cell filtering */ -#define SUNI_DS3_DSCR 0x04 /* Disable payload descrambling */ -#define SUNI_DS3_OOCDV 0x02 /* Cell delineation state */ -#define SUNI_DS3_FIFORST 0x01 /* Cell FIFO reset */ - -/* - * RXCP Interrupt Enable/Status - */ -#define SUNI_DS3_OOCDE 0x80 /* Intr enable, change in CDS */ -#define SUNI_DS3_HCSE 0x40 /* Intr enable, corr HCS errors */ -#define SUNI_DS3_FIFOE 0x20 /* Intr enable, unco HCS errors */ -#define SUNI_DS3_OOCDI 0x10 /* SYNC state */ -#define SUNI_DS3_UHCSI 0x08 /* Uncorr. HCS errors detected */ -#define SUNI_DS3_COCAI 0x04 /* Corr. HCS errors detected */ -#define SUNI_DS3_FOVRI 0x02 /* FIFO overrun */ -#define SUNI_DS3_FUDRI 0x01 /* FIFO underrun */ - -///////////////////SUNI_PM7345 PHY DEFINE END ///////////////////////////// - -/* ia_eeprom define*/ -#define MEM_SIZE_MASK 0x000F /* mask of 4 bits defining memory size*/ -#define MEM_SIZE_128K 0x0000 /* board has 128k buffer */ -#define MEM_SIZE_512K 0x0001 /* board has 512K of buffer */ -#define MEM_SIZE_1M 0x0002 /* board has 1M of buffer */ - /* 0x3 to 0xF are reserved for future */ - -#define FE_MASK 0x00F0 /* mask of 4 bits defining FE type */ -#define FE_MULTI_MODE 0x0000 /* 155 MBit multimode fiber */ -#define FE_SINGLE_MODE 0x0010 /* 155 MBit single mode laser */ -#define FE_UTP_OPTION 0x0020 /* 155 MBit UTP front end */ - -#define NOVRAM_SIZE 64 -#define CMD_LEN 10 - -/*********** - * - * Switches and defines for header files. - * - * The following defines are used to turn on and off - * various options in the header files. Primarily useful - * for debugging. - * - ***********/ - -/* - * a list of the commands that can be sent to the NOVRAM - */ - -#define EXTEND 0x100 -#define IAWRITE 0x140 -#define IAREAD 0x180 -#define ERASE 0x1c0 - -#define EWDS 0x00 -#define WRAL 0x10 -#define ERAL 0x20 -#define EWEN 0x30 - -/* - * these bits duplicate the hw_flip.h register settings - * note: how the data in / out bits are defined in the flipper specification - */ - -#define NVCE 0x02 -#define NVSK 0x01 -#define NVDO 0x08 -#define NVDI 0x04 -/*********************** - * - * This define ands the value and the current config register and puts - * the result in the config register - * - ***********************/ - -#define CFG_AND(val) { \ - u32 t; \ - t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ - t &= (val); \ - writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ - } - -/*********************** - * - * This define ors the value and the current config register and puts - * the result in the config register - * - ***********************/ - -#define CFG_OR(val) { \ - u32 t; \ - t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); \ - t |= (val); \ - writel(t, iadev->reg+IPHASE5575_EEPROM_ACCESS); \ - } - -/*********************** - * - * Send a command to the NOVRAM, the command is in cmd. - * - * clear CE and SK. Then assert CE. - * Clock each of the command bits out in the correct order with SK - * exit with CE still asserted - * - ***********************/ - -#define NVRAM_CMD(cmd) { \ - int i; \ - u_short c = cmd; \ - CFG_AND(~(NVCE|NVSK)); \ - CFG_OR(NVCE); \ - for (i=0; ireg+IPHASE5575_EEPROM_ACCESS); \ - value = (_t & NVDO) ? 1 : 0; \ - } - - -#endif /* IPHASE_H */ diff --git a/drivers/atm/midway.h b/drivers/atm/midway.h deleted file mode 100644 index d47307adc0c9..000000000000 --- a/drivers/atm/midway.h +++ /dev/null @@ -1,266 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */ - -/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ - - -#ifndef DRIVERS_ATM_MIDWAY_H -#define DRIVERS_ATM_MIDWAY_H - - -#define NR_VCI 1024 /* number of VCIs */ -#define NR_VCI_LD 10 /* log2(NR_VCI) */ -#define NR_DMA_RX 512 /* RX DMA queue entries */ -#define NR_DMA_TX 512 /* TX DMA queue entries */ -#define NR_SERVICE NR_VCI /* service list size */ -#define NR_CHAN 8 /* number of TX channels */ -#define TS_CLOCK 25000000 /* traffic shaper clock (cell/sec) */ - -#define MAP_MAX_SIZE 0x00400000 /* memory window for max config */ -#define EPROM_SIZE 0x00010000 -#define MEM_VALID 0xffc00000 /* mask base address with this */ -#define PHY_BASE 0x00020000 /* offset of PHY register are */ -#define REG_BASE 0x00040000 /* offset of Midway register area */ -#define RAM_BASE 0x00200000 /* offset of RAM area */ -#define RAM_INCREMENT 0x00020000 /* probe for RAM every 128kB */ - -#define MID_VCI_BASE RAM_BASE -#define MID_DMA_RX_BASE (MID_VCI_BASE+NR_VCI*16) -#define MID_DMA_TX_BASE (MID_DMA_RX_BASE+NR_DMA_RX*8) -#define MID_SERVICE_BASE (MID_DMA_TX_BASE+NR_DMA_TX*8) -#define MID_FREE_BASE (MID_SERVICE_BASE+NR_SERVICE*4) - -#define MAC_LEN 6 /* atm.h */ - -#define MID_MIN_BUF_SIZE (1024) /* 1 kB is minimum */ -#define MID_MAX_BUF_SIZE (128*1024) /* 128 kB is maximum */ - -#define RX_DESCR_SIZE 1 /* RX PDU descr is 1 longword */ -#define TX_DESCR_SIZE 2 /* TX PDU descr is 2 longwords */ -#define AAL5_TRAILER (ATM_AAL5_TRAILER/4) /* AAL5 trailer is 2 longwords */ - -#define TX_GAP 8 /* TX buffer gap (words) */ - -/* - * Midway Reset/ID - * - * All values read-only. Writing to this register resets Midway chip. - */ - -#define MID_RES_ID_MCON 0x00 /* Midway Reset/ID */ - -#define MID_ID 0xf0000000 /* Midway version */ -#define MID_SHIFT 24 -#define MID_MOTHER_ID 0x00000700 /* mother board id */ -#define MID_MOTHER_SHIFT 8 -#define MID_CON_TI 0x00000080 /* 0: normal ctrl; 1: SABRE */ -#define MID_CON_SUNI 0x00000040 /* 0: UTOPIA; 1: SUNI */ -#define MID_CON_V6 0x00000020 /* 0: non-pipel UTOPIA (required iff - !CON_SUNI; 1: UTOPIA */ -#define DAUGHTER_ID 0x0000001f /* daughter board id */ - -/* - * Interrupt Status Acknowledge, Interrupt Status & Interrupt Enable - */ - -#define MID_ISA 0x01 /* Interrupt Status Acknowledge */ -#define MID_IS 0x02 /* Interrupt Status */ -#define MID_IE 0x03 /* Interrupt Enable */ - -#define MID_TX_COMPLETE_7 0x00010000 /* channel N completed a PDU */ -#define MID_TX_COMPLETE_6 0x00008000 /* transmission */ -#define MID_TX_COMPLETE_5 0x00004000 -#define MID_TX_COMPLETE_4 0x00002000 -#define MID_TX_COMPLETE_3 0x00001000 -#define MID_TX_COMPLETE_2 0x00000800 -#define MID_TX_COMPLETE_1 0x00000400 -#define MID_TX_COMPLETE_0 0x00000200 -#define MID_TX_COMPLETE 0x0001fe00 /* any TX */ -#define MID_TX_DMA_OVFL 0x00000100 /* DMA to adapter overflow */ -#define MID_TX_IDENT_MISM 0x00000080 /* TX: ident mismatch => halted */ -#define MID_DMA_LERR_ACK 0x00000040 /* LERR - SBus ? */ -#define MID_DMA_ERR_ACK 0x00000020 /* DMA error */ -#define MID_RX_DMA_COMPLETE 0x00000010 /* DMA to host done */ -#define MID_TX_DMA_COMPLETE 0x00000008 /* DMA from host done */ -#define MID_SERVICE 0x00000004 /* something in service list */ -#define MID_SUNI_INT 0x00000002 /* interrupt from SUNI */ -#define MID_STAT_OVFL 0x00000001 /* statistics overflow */ - -/* - * Master Control/Status - */ - -#define MID_MC_S 0x04 - -#define MID_INT_SELECT 0x000001C0 /* Interrupt level (000: off) */ -#define MID_INT_SEL_SHIFT 6 -#define MID_TX_LOCK_MODE 0x00000020 /* 0: streaming; 1: TX ovfl->lock */ -#define MID_DMA_ENABLE 0x00000010 /* R: 0: disable; 1: enable - W: 0: no change; 1: enable */ -#define MID_TX_ENABLE 0x00000008 /* R: 0: TX disabled; 1: enabled - W: 0: no change; 1: enable */ -#define MID_RX_ENABLE 0x00000004 /* like TX */ -#define MID_WAIT_1MS 0x00000002 /* R: 0: timer not running; 1: running - W: 0: no change; 1: no interrupts - for 1 ms */ -#define MID_WAIT_500US 0x00000001 /* like WAIT_1MS, but 0.5 ms */ - -/* - * Statistics - * - * Cleared when reading. - */ - -#define MID_STAT 0x05 - -#define MID_VCI_TRASH 0xFFFF0000 /* trashed cells because of VCI mode */ -#define MID_VCI_TRASH_SHIFT 16 -#define MID_OVFL_TRASH 0x0000FFFF /* trashed cells because of overflow */ - -/* - * Address registers - */ - -#define MID_SERV_WRITE 0x06 /* free pos in service area (R, 10 bits) */ -#define MID_DMA_ADDR 0x07 /* virtual DMA address (R, 32 bits) */ -#define MID_DMA_WR_RX 0x08 /* (RW, 9 bits) */ -#define MID_DMA_RD_RX 0x09 -#define MID_DMA_WR_TX 0x0A -#define MID_DMA_RD_TX 0x0B - -/* - * Transmit Place Registers (0x10+4*channel) - */ - -#define MID_TX_PLACE(c) (0x10+4*(c)) - -#define MID_SIZE 0x00003800 /* size, N*256 x 32 bit */ -#define MID_SIZE_SHIFT 11 -#define MID_LOCATION 0x000007FF /* location in adapter memory (word) */ - -#define MID_LOC_SKIP 8 /* 8 bits of location are always zero - (applies to all uses of location) */ - -/* - * Transmit ReadPtr Registers (0x11+4*channel) - */ - -#define MID_TX_RDPTR(c) (0x11+4*(c)) - -#define MID_READ_PTR 0x00007FFF /* next word for PHY */ - -/* - * Transmit DescrStart Registers (0x12+4*channel) - */ - -#define MID_TX_DESCRSTART(c) (0x12+4*(c)) - -#define MID_DESCR_START 0x00007FFF /* seg buffer being DMAed */ - -#define ENI155_MAGIC 0xa54b872d - -struct midway_eprom { - unsigned char mac[MAC_LEN],inv_mac[MAC_LEN]; - unsigned char pad[36]; - u32 serial,inv_serial; - u32 magic,inv_magic; -}; - - -/* - * VCI table entry - */ - -#define MID_VCI_IN_SERVICE 0x00000001 /* set if VCI is currently in - service list */ -#define MID_VCI_SIZE 0x00038000 /* reassembly buffer size, - 2* kB */ -#define MID_VCI_SIZE_SHIFT 15 -#define MID_VCI_LOCATION 0x1ffc0000 /* buffer location */ -#define MID_VCI_LOCATION_SHIFT 18 -#define MID_VCI_PTI_MODE 0x20000000 /* 0: trash, 1: preserve */ -#define MID_VCI_MODE 0xc0000000 -#define MID_VCI_MODE_SHIFT 30 -#define MID_VCI_READ 0x00007fff -#define MID_VCI_READ_SHIFT 0 -#define MID_VCI_DESCR 0x7fff0000 -#define MID_VCI_DESCR_SHIFT 16 -#define MID_VCI_COUNT 0x000007ff -#define MID_VCI_COUNT_SHIFT 0 -#define MID_VCI_STATE 0x0000c000 -#define MID_VCI_STATE_SHIFT 14 -#define MID_VCI_WRITE 0x7fff0000 -#define MID_VCI_WRITE_SHIFT 16 - -#define MID_MODE_TRASH 0 -#define MID_MODE_RAW 1 -#define MID_MODE_AAL5 2 - -/* - * Reassembly buffer descriptor - */ - -#define MID_RED_COUNT 0x000007ff -#define MID_RED_CRC_ERR 0x00000800 -#define MID_RED_T 0x00001000 -#define MID_RED_CE 0x00010000 -#define MID_RED_CLP 0x01000000 -#define MID_RED_IDEN 0xfe000000 -#define MID_RED_SHIFT 25 - -#define MID_RED_RX_ID 0x1b /* constant identifier */ - -/* - * Segmentation buffer descriptor - */ - -#define MID_SEG_COUNT MID_RED_COUNT -#define MID_SEG_RATE 0x01f80000 -#define MID_SEG_RATE_SHIFT 19 -#define MID_SEG_PR 0x06000000 -#define MID_SEG_PR_SHIFT 25 -#define MID_SEG_AAL5 0x08000000 -#define MID_SEG_ID 0xf0000000 -#define MID_SEG_ID_SHIFT 28 -#define MID_SEG_MAX_RATE 63 - -#define MID_SEG_CLP 0x00000001 -#define MID_SEG_PTI 0x0000000e -#define MID_SEG_PTI_SHIFT 1 -#define MID_SEG_VCI 0x00003ff0 -#define MID_SEG_VCI_SHIFT 4 - -#define MID_SEG_TX_ID 0xb /* constant identifier */ - -/* - * DMA entry - */ - -#define MID_DMA_COUNT 0xffff0000 -#define MID_DMA_COUNT_SHIFT 16 -#define MID_DMA_END 0x00000020 -#define MID_DMA_TYPE 0x0000000f - -#define MID_DT_JK 0x3 -#define MID_DT_WORD 0x0 -#define MID_DT_2W 0x7 -#define MID_DT_4W 0x4 -#define MID_DT_8W 0x5 -#define MID_DT_16W 0x6 -#define MID_DT_2WM 0xf -#define MID_DT_4WM 0xc -#define MID_DT_8WM 0xd -#define MID_DT_16WM 0xe - -/* only for RX*/ -#define MID_DMA_VCI 0x0000ffc0 -#define MID_DMA_VCI_SHIFT 6 - -/* only for TX */ -#define MID_DMA_CHAN 0x000001c0 -#define MID_DMA_CHAN_SHIFT 6 - -#define MID_DT_BYTE 0x1 -#define MID_DT_HWORD 0x2 - -#endif diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h deleted file mode 100644 index 1b7f1dfc1735..000000000000 --- a/drivers/atm/nicstar.h +++ /dev/null @@ -1,759 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * nicstar.h - * - * Header file for the nicstar device driver. - * - * Author: Rui Prior (rprior@inescn.pt) - * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 - * - * (C) INESC 1998 - */ - -#ifndef _LINUX_NICSTAR_H_ -#define _LINUX_NICSTAR_H_ - -/* Includes */ - -#include -#include -#include -#include -#include -#include -#include - -/* Options */ - -#define NS_MAX_CARDS 4 /* Maximum number of NICStAR based cards - controlled by the device driver. Must - be <= 5 */ - -#undef RCQ_SUPPORT /* Do not define this for now */ - -#define NS_TST_NUM_ENTRIES 2340 /* + 1 for return */ -#define NS_TST_RESERVED 340 /* N. entries reserved for UBR/ABR/VBR */ - -#define NS_SMBUFSIZE 48 /* 48, 96, 240 or 2048 */ -#define NS_LGBUFSIZE 16384 /* 2048, 4096, 8192 or 16384 */ -#define NS_RSQSIZE 8192 /* 2048, 4096 or 8192 */ -#define NS_VPIBITS 2 /* 0, 1, 2, or 8 */ - -#define NS_MAX_RCTSIZE 4096 /* Number of entries. 4096 or 16384. - Define 4096 only if (all) your card(s) - have 32K x 32bit SRAM, in which case - setting this to 16384 will just waste a - lot of memory. - Setting this to 4096 for a card with - 128K x 32bit SRAM will limit the maximum - VCI. */ - - /*#define NS_PCI_LATENCY 64*//* Must be a multiple of 32 */ - - /* Number of buffers initially allocated */ -#define NUM_SB 32 /* Must be even */ -#define NUM_LB 24 /* Must be even */ -#define NUM_HB 8 /* Pre-allocated huge buffers */ -#define NUM_IOVB 48 /* Iovec buffers */ - - /* Lower level for count of buffers */ -#define MIN_SB 8 /* Must be even */ -#define MIN_LB 8 /* Must be even */ -#define MIN_HB 6 -#define MIN_IOVB 8 - - /* Upper level for count of buffers */ -#define MAX_SB 64 /* Must be even, <= 508 */ -#define MAX_LB 48 /* Must be even, <= 508 */ -#define MAX_HB 10 -#define MAX_IOVB 80 - - /* These are the absolute maximum allowed for the ioctl() */ -#define TOP_SB 256 /* Must be even, <= 508 */ -#define TOP_LB 128 /* Must be even, <= 508 */ -#define TOP_HB 64 -#define TOP_IOVB 256 - -#define MAX_TBD_PER_VC 1 /* Number of TBDs before a TSR */ -#define MAX_TBD_PER_SCQ 10 /* Only meaningful for variable rate SCQs */ - -#undef ENABLE_TSQFIE - -#define SCQFULL_TIMEOUT (5 * HZ) - -#define NS_POLL_PERIOD (HZ) - -#define PCR_TOLERANCE (1.0001) - -/* ESI stuff */ - -#define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C -#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6 - -/* #defines */ - -#define NS_IOREMAP_SIZE 4096 - -/* - * BUF_XX distinguish the Rx buffers depending on their (small/large) size. - * BUG_SM and BUG_LG are both used by the driver and the device. - * BUF_NONE is only used by the driver. - */ -#define BUF_SM 0x00000000 /* These two are used for push_rxbufs() */ -#define BUF_LG 0x00000001 /* CMD, Write_FreeBufQ, LBUF bit */ -#define BUF_NONE 0xffffffff /* Software only: */ - -#define NS_HBUFSIZE 65568 /* Size of max. AAL5 PDU */ -#define NS_MAX_IOVECS (2 + (65568 - NS_SMBUFSIZE) / \ - (NS_LGBUFSIZE - (NS_LGBUFSIZE % 48))) -#define NS_IOVBUFSIZE (NS_MAX_IOVECS * (sizeof(struct iovec))) - -#define NS_SMBUFSIZE_USABLE (NS_SMBUFSIZE - NS_SMBUFSIZE % 48) -#define NS_LGBUFSIZE_USABLE (NS_LGBUFSIZE - NS_LGBUFSIZE % 48) - -#define NS_AAL0_HEADER (ATM_AAL0_SDU - ATM_CELL_PAYLOAD) /* 4 bytes */ - -#define NS_SMSKBSIZE (NS_SMBUFSIZE + NS_AAL0_HEADER) -#define NS_LGSKBSIZE (NS_SMBUFSIZE + NS_LGBUFSIZE) - -/* NICStAR structures located in host memory */ - -/* - * RSQ - Receive Status Queue - * - * Written by the NICStAR, read by the device driver. - */ - -typedef struct ns_rsqe { - u32 word_1; - u32 buffer_handle; - u32 final_aal5_crc32; - u32 word_4; -} ns_rsqe; - -#define ns_rsqe_vpi(ns_rsqep) \ - ((le32_to_cpu((ns_rsqep)->word_1) & 0x00FF0000) >> 16) -#define ns_rsqe_vci(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_1) & 0x0000FFFF) - -#define NS_RSQE_VALID 0x80000000 -#define NS_RSQE_NZGFC 0x00004000 -#define NS_RSQE_EOPDU 0x00002000 -#define NS_RSQE_BUFSIZE 0x00001000 -#define NS_RSQE_CONGESTION 0x00000800 -#define NS_RSQE_CLP 0x00000400 -#define NS_RSQE_CRCERR 0x00000200 - -#define NS_RSQE_BUFSIZE_SM 0x00000000 -#define NS_RSQE_BUFSIZE_LG 0x00001000 - -#define ns_rsqe_valid(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_VALID) -#define ns_rsqe_nzgfc(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_NZGFC) -#define ns_rsqe_eopdu(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_EOPDU) -#define ns_rsqe_bufsize(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_BUFSIZE) -#define ns_rsqe_congestion(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CONGESTION) -#define ns_rsqe_clp(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CLP) -#define ns_rsqe_crcerr(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & NS_RSQE_CRCERR) - -#define ns_rsqe_cellcount(ns_rsqep) \ - (le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF) -#define ns_rsqe_init(ns_rsqep) \ - ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000)) - -#define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16) -#define NS_RSQ_ALIGNMENT NS_RSQSIZE - -/* - * RCQ - Raw Cell Queue - * - * Written by the NICStAR, read by the device driver. - */ - -typedef struct cell_payload { - u32 word[12]; -} cell_payload; - -typedef struct ns_rcqe { - u32 word_1; - u32 word_2; - u32 word_3; - u32 word_4; - cell_payload payload; -} ns_rcqe; - -#define NS_RCQE_SIZE 64 /* bytes */ - -#define ns_rcqe_islast(ns_rcqep) \ - (le32_to_cpu((ns_rcqep)->word_2) != 0x00000000) -#define ns_rcqe_cellheader(ns_rcqep) \ - (le32_to_cpu((ns_rcqep)->word_1)) -#define ns_rcqe_nextbufhandle(ns_rcqep) \ - (le32_to_cpu((ns_rcqep)->word_2)) - -/* - * SCQ - Segmentation Channel Queue - * - * Written by the device driver, read by the NICStAR. - */ - -typedef struct ns_scqe { - u32 word_1; - u32 word_2; - u32 word_3; - u32 word_4; -} ns_scqe; - - /* NOTE: SCQ entries can be either a TBD (Transmit Buffer Descriptors) - or TSR (Transmit Status Requests) */ - -#define NS_SCQE_TYPE_TBD 0x00000000 -#define NS_SCQE_TYPE_TSR 0x80000000 - -#define NS_TBD_EOPDU 0x40000000 -#define NS_TBD_AAL0 0x00000000 -#define NS_TBD_AAL34 0x04000000 -#define NS_TBD_AAL5 0x08000000 - -#define NS_TBD_VPI_MASK 0x0FF00000 -#define NS_TBD_VCI_MASK 0x000FFFF0 -#define NS_TBD_VC_MASK (NS_TBD_VPI_MASK | NS_TBD_VCI_MASK) - -#define NS_TBD_VPI_SHIFT 20 -#define NS_TBD_VCI_SHIFT 4 - -#define ns_tbd_mkword_1(flags, m, n, buflen) \ - (cpu_to_le32((flags) | (m) << 23 | (n) << 16 | (buflen))) -#define ns_tbd_mkword_1_novbr(flags, buflen) \ - (cpu_to_le32((flags) | (buflen) | 0x00810000)) -#define ns_tbd_mkword_3(control, pdulen) \ - (cpu_to_le32((control) << 16 | (pdulen))) -#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \ - (cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp))) - -#define NS_TSR_INTENABLE 0x20000000 - -#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */ - -#define ns_tsr_mkword_1(flags) \ - (cpu_to_le32(NS_SCQE_TYPE_TSR | (flags))) -#define ns_tsr_mkword_2(scdi, scqi) \ - (cpu_to_le32((scdi) << 16 | 0x00008000 | (scqi))) - -#define ns_scqe_is_tsr(ns_scqep) \ - (le32_to_cpu((ns_scqep)->word_1) & NS_SCQE_TYPE_TSR) - -#define VBR_SCQ_NUM_ENTRIES 512 -#define VBR_SCQSIZE 8192 -#define CBR_SCQ_NUM_ENTRIES 64 -#define CBR_SCQSIZE 1024 - -#define NS_SCQE_SIZE 16 - -/* - * TSQ - Transmit Status Queue - * - * Written by the NICStAR, read by the device driver. - */ - -typedef struct ns_tsi { - u32 word_1; - u32 word_2; -} ns_tsi; - - /* NOTE: The first word can be a status word copied from the TSR which - originated the TSI, or a timer overflow indicator. In this last - case, the value of the first word is all zeroes. */ - -#define NS_TSI_EMPTY 0x80000000 -#define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF - -#define ns_tsi_isempty(ns_tsip) \ - (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_EMPTY) -#define ns_tsi_gettimestamp(ns_tsip) \ - (le32_to_cpu((ns_tsip)->word_2) & NS_TSI_TIMESTAMP_MASK) - -#define ns_tsi_init(ns_tsip) \ - ((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY)) - -#define NS_TSQSIZE 8192 -#define NS_TSQ_NUM_ENTRIES 1024 -#define NS_TSQ_ALIGNMENT 8192 - -#define NS_TSI_SCDISVBR NS_TSR_SCDISVBR - -#define ns_tsi_tmrof(ns_tsip) \ - (le32_to_cpu((ns_tsip)->word_1) == 0x00000000) -#define ns_tsi_getscdindex(ns_tsip) \ - ((le32_to_cpu((ns_tsip)->word_1) & 0xFFFF0000) >> 16) -#define ns_tsi_getscqpos(ns_tsip) \ - (le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF) - -/* NICStAR structures located in local SRAM */ - -/* - * RCT - Receive Connection Table - * - * Written by both the NICStAR and the device driver. - */ - -typedef struct ns_rcte { - u32 word_1; - u32 buffer_handle; - u32 dma_address; - u32 aal5_crc32; -} ns_rcte; - -#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */ -#define NS_RCTE_NZGFC 0x00100000 -#define NS_RCTE_CONNECTOPEN 0x00080000 -#define NS_RCTE_AALMASK 0x00070000 -#define NS_RCTE_AAL0 0x00000000 -#define NS_RCTE_AAL34 0x00010000 -#define NS_RCTE_AAL5 0x00020000 -#define NS_RCTE_RCQ 0x00030000 -#define NS_RCTE_RAWCELLINTEN 0x00008000 -#define NS_RCTE_RXCONSTCELLADDR 0x00004000 -#define NS_RCTE_BUFFVALID 0x00002000 -#define NS_RCTE_FBDSIZE 0x00001000 -#define NS_RCTE_EFCI 0x00000800 -#define NS_RCTE_CLP 0x00000400 -#define NS_RCTE_CRCERROR 0x00000200 -#define NS_RCTE_CELLCOUNT_MASK 0x000001FF - -#define NS_RCTE_FBDSIZE_SM 0x00000000 -#define NS_RCTE_FBDSIZE_LG 0x00001000 - -#define NS_RCT_ENTRY_SIZE 4 /* Number of dwords */ - - /* NOTE: We could make macros to contruct the first word of the RCTE, - but that doesn't seem to make much sense... */ - -/* - * FBD - Free Buffer Descriptor - * - * Written by the device driver using via the command register. - */ - -typedef struct ns_fbd { - u32 buffer_handle; - u32 dma_address; -} ns_fbd; - -/* - * TST - Transmit Schedule Table - * - * Written by the device driver. - */ - -typedef u32 ns_tste; - -#define NS_TST_OPCODE_MASK 0x60000000 - -#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */ -#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */ -#define NS_TST_OPCODE_VARIABLE 0x40000000 -#define NS_TST_OPCODE_END 0x60000000 /* Jump */ - -#define ns_tste_make(opcode, sramad) (opcode | sramad) - - /* NOTE: - - - When the opcode is FIXED, sramad specifies the SRAM address of the - SCD for that fixed rate channel. - - When the opcode is END, sramad specifies the SRAM address of the - location of the next TST entry to read. - */ - -/* - * SCD - Segmentation Channel Descriptor - * - * Written by both the device driver and the NICStAR - */ - -typedef struct ns_scd { - u32 word_1; - u32 word_2; - u32 partial_aal5_crc; - u32 reserved; - ns_scqe cache_a; - ns_scqe cache_b; -} ns_scd; - -#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */ -#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */ -#define NS_SCD_TAIL_MASK_VAR 0x00001FF0 -#define NS_SCD_TAIL_MASK_FIX 0x000003F0 -#define NS_SCD_HEAD_MASK_VAR 0x00001FF0 -#define NS_SCD_HEAD_MASK_FIX 0x000003F0 -#define NS_SCD_XMITFOREVER 0x02000000 - - /* NOTE: There are other fields in word 2 of the SCD, but as they should - not be needed in the device driver they are not defined here. */ - -/* NICStAR local SRAM memory map */ - -#define NS_RCT 0x00000 -#define NS_RCT_32_END 0x03FFF -#define NS_RCT_128_END 0x0FFFF -#define NS_UNUSED_32 0x04000 -#define NS_UNUSED_128 0x10000 -#define NS_UNUSED_END 0x1BFFF -#define NS_TST_FRSCD 0x1C000 -#define NS_TST_FRSCD_END 0x1E7DB -#define NS_VRSCD2 0x1E7DC -#define NS_VRSCD2_END 0x1E7E7 -#define NS_VRSCD1 0x1E7E8 -#define NS_VRSCD1_END 0x1E7F3 -#define NS_VRSCD0 0x1E7F4 -#define NS_VRSCD0_END 0x1E7FF -#define NS_RXFIFO 0x1E800 -#define NS_RXFIFO_END 0x1F7FF -#define NS_SMFBQ 0x1F800 -#define NS_SMFBQ_END 0x1FBFF -#define NS_LGFBQ 0x1FC00 -#define NS_LGFBQ_END 0x1FFFF - -/* NISCtAR operation registers */ - -/* See Section 3.4 of `IDT77211 NICStAR User Manual' from www.idt.com */ - -enum ns_regs { - DR0 = 0x00, /* Data Register 0 R/W */ - DR1 = 0x04, /* Data Register 1 W */ - DR2 = 0x08, /* Data Register 2 W */ - DR3 = 0x0C, /* Data Register 3 W */ - CMD = 0x10, /* Command W */ - CFG = 0x14, /* Configuration R/W */ - STAT = 0x18, /* Status R/W */ - RSQB = 0x1C, /* Receive Status Queue Base W */ - RSQT = 0x20, /* Receive Status Queue Tail R */ - RSQH = 0x24, /* Receive Status Queue Head W */ - CDC = 0x28, /* Cell Drop Counter R/clear */ - VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */ - ICC = 0x30, /* Invalid Cell Count R/clear */ - RAWCT = 0x34, /* Raw Cell Tail R */ - TMR = 0x38, /* Timer R */ - TSTB = 0x3C, /* Transmit Schedule Table Base R/W */ - TSQB = 0x40, /* Transmit Status Queue Base W */ - TSQT = 0x44, /* Transmit Status Queue Tail R */ - TSQH = 0x48, /* Transmit Status Queue Head W */ - GP = 0x4C, /* General Purpose R/W */ - VPM = 0x50 /* VPI/VCI Mask W */ -}; - -/* NICStAR commands issued to the CMD register */ - -/* Top 4 bits are command opcode, lower 28 are parameters. */ - -#define NS_CMD_NO_OPERATION 0x00000000 - /* params always 0 */ - -#define NS_CMD_OPENCLOSE_CONNECTION 0x20000000 - /* b19{1=open,0=close} b18-2{SRAM addr} */ - -#define NS_CMD_WRITE_SRAM 0x40000000 - /* b18-2{SRAM addr} b1-0{burst size} */ - -#define NS_CMD_READ_SRAM 0x50000000 - /* b18-2{SRAM addr} */ - -#define NS_CMD_WRITE_FREEBUFQ 0x60000000 - /* b0{large buf indicator} */ - -#define NS_CMD_READ_UTILITY 0x80000000 - /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */ - -#define NS_CMD_WRITE_UTILITY 0x90000000 - /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */ - -#define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000) -#define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION - -/* NICStAR configuration bits */ - -#define NS_CFG_SWRST 0x80000000 /* Software Reset */ -#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */ -#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */ -#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */ -#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue - Interrupt Enable */ -#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */ -#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */ -#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */ -#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */ -#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */ -#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */ -#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt - Handling */ -#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */ -#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full - Interrupt Enable */ -#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */ -#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt - Enable */ -#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */ -#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt - Enable */ -#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt - Enable */ -#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */ -#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full - Interrupt Enable */ -#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */ - -#define NS_CFG_SMBUFSIZE_48 0x00000000 -#define NS_CFG_SMBUFSIZE_96 0x08000000 -#define NS_CFG_SMBUFSIZE_240 0x10000000 -#define NS_CFG_SMBUFSIZE_2048 0x18000000 - -#define NS_CFG_LGBUFSIZE_2048 0x00000000 -#define NS_CFG_LGBUFSIZE_4096 0x02000000 -#define NS_CFG_LGBUFSIZE_8192 0x04000000 -#define NS_CFG_LGBUFSIZE_16384 0x06000000 - -#define NS_CFG_RSQSIZE_2048 0x00000000 -#define NS_CFG_RSQSIZE_4096 0x00400000 -#define NS_CFG_RSQSIZE_8192 0x00800000 - -#define NS_CFG_VPIBITS_0 0x00000000 -#define NS_CFG_VPIBITS_1 0x00040000 -#define NS_CFG_VPIBITS_2 0x00080000 -#define NS_CFG_VPIBITS_8 0x000C0000 - -#define NS_CFG_RCTSIZE_4096_ENTRIES 0x00000000 -#define NS_CFG_RCTSIZE_8192_ENTRIES 0x00010000 -#define NS_CFG_RCTSIZE_16384_ENTRIES 0x00020000 - -#define NS_CFG_RXINT_NOINT 0x00000000 -#define NS_CFG_RXINT_NODELAY 0x00001000 -#define NS_CFG_RXINT_314US 0x00002000 -#define NS_CFG_RXINT_624US 0x00003000 -#define NS_CFG_RXINT_899US 0x00004000 - -/* NICStAR STATus bits */ - -#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */ -#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */ -#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */ -#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */ -#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */ -#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */ -#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */ -#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */ -#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */ -#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */ -#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */ -#define NS_STAT_EOPDU 0x00000020 /* End of PDU */ -#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */ -#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */ -#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */ -#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */ - -#define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23) -#define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15) - -/* #defines which depend on other #defines */ - -#define NS_TST0 NS_TST_FRSCD -#define NS_TST1 (NS_TST_FRSCD + NS_TST_NUM_ENTRIES + 1) - -#define NS_FRSCD (NS_TST1 + NS_TST_NUM_ENTRIES + 1) -#define NS_FRSCD_SIZE 12 /* 12 dwords */ -#define NS_FRSCD_NUM ((NS_TST_FRSCD_END + 1 - NS_FRSCD) / NS_FRSCD_SIZE) - -#if (NS_SMBUFSIZE == 48) -#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_48 -#elif (NS_SMBUFSIZE == 96) -#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_96 -#elif (NS_SMBUFSIZE == 240) -#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_240 -#elif (NS_SMBUFSIZE == 2048) -#define NS_CFG_SMBUFSIZE NS_CFG_SMBUFSIZE_2048 -#else -#error NS_SMBUFSIZE is incorrect in nicstar.h -#endif /* NS_SMBUFSIZE */ - -#if (NS_LGBUFSIZE == 2048) -#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_2048 -#elif (NS_LGBUFSIZE == 4096) -#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_4096 -#elif (NS_LGBUFSIZE == 8192) -#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_8192 -#elif (NS_LGBUFSIZE == 16384) -#define NS_CFG_LGBUFSIZE NS_CFG_LGBUFSIZE_16384 -#else -#error NS_LGBUFSIZE is incorrect in nicstar.h -#endif /* NS_LGBUFSIZE */ - -#if (NS_RSQSIZE == 2048) -#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_2048 -#elif (NS_RSQSIZE == 4096) -#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_4096 -#elif (NS_RSQSIZE == 8192) -#define NS_CFG_RSQSIZE NS_CFG_RSQSIZE_8192 -#else -#error NS_RSQSIZE is incorrect in nicstar.h -#endif /* NS_RSQSIZE */ - -#if (NS_VPIBITS == 0) -#define NS_CFG_VPIBITS NS_CFG_VPIBITS_0 -#elif (NS_VPIBITS == 1) -#define NS_CFG_VPIBITS NS_CFG_VPIBITS_1 -#elif (NS_VPIBITS == 2) -#define NS_CFG_VPIBITS NS_CFG_VPIBITS_2 -#elif (NS_VPIBITS == 8) -#define NS_CFG_VPIBITS NS_CFG_VPIBITS_8 -#else -#error NS_VPIBITS is incorrect in nicstar.h -#endif /* NS_VPIBITS */ - -#ifdef RCQ_SUPPORT -#define NS_CFG_RAWIE_OPT NS_CFG_RAWIE -#else -#define NS_CFG_RAWIE_OPT 0x00000000 -#endif /* RCQ_SUPPORT */ - -#ifdef ENABLE_TSQFIE -#define NS_CFG_TSQFIE_OPT NS_CFG_TSQFIE -#else -#define NS_CFG_TSQFIE_OPT 0x00000000 -#endif /* ENABLE_TSQFIE */ - -/* PCI stuff */ - -#ifndef PCI_VENDOR_ID_IDT -#define PCI_VENDOR_ID_IDT 0x111D -#endif /* PCI_VENDOR_ID_IDT */ - -#ifndef PCI_DEVICE_ID_IDT_IDT77201 -#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 -#endif /* PCI_DEVICE_ID_IDT_IDT77201 */ - -/* Device driver structures */ - -struct ns_skb_prv { - u32 buf_type; /* BUF_SM/BUF_LG/BUF_NONE */ - u32 dma; - int iovcnt; -}; - -#define NS_PRV_BUFTYPE(skb) \ - (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->buf_type) -#define NS_PRV_DMA(skb) \ - (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->dma) -#define NS_PRV_IOVCNT(skb) \ - (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->iovcnt) - -typedef struct tsq_info { - void *org; - dma_addr_t dma; - ns_tsi *base; - ns_tsi *next; - ns_tsi *last; -} tsq_info; - -typedef struct scq_info { - void *org; - dma_addr_t dma; - ns_scqe *base; - ns_scqe *last; - ns_scqe *next; - volatile ns_scqe *tail; /* Not related to the nicstar register */ - unsigned num_entries; - struct sk_buff **skb; /* Pointer to an array of pointers - to the sk_buffs used for tx */ - u32 scd; /* SRAM address of the corresponding - SCD */ - int tbd_count; /* Only meaningful on variable rate */ - wait_queue_head_t scqfull_waitq; - volatile char full; /* SCQ full indicator */ - spinlock_t lock; /* SCQ spinlock */ -} scq_info; - -typedef struct rsq_info { - void *org; - dma_addr_t dma; - ns_rsqe *base; - ns_rsqe *next; - ns_rsqe *last; -} rsq_info; - -typedef struct skb_pool { - volatile int count; /* number of buffers in the queue */ - struct sk_buff_head queue; -} skb_pool; - -/* NOTE: for small and large buffer pools, the count is not used, as the - actual value used for buffer management is the one read from the - card. */ - -typedef struct vc_map { - volatile unsigned int tx:1; /* TX vc? */ - volatile unsigned int rx:1; /* RX vc? */ - struct atm_vcc *tx_vcc, *rx_vcc; - struct sk_buff *rx_iov; /* RX iovector skb */ - scq_info *scq; /* To keep track of the SCQ */ - u32 cbr_scd; /* SRAM address of the corresponding - SCD. 0x00000000 for UBR/VBR/ABR */ - int tbd_count; -} vc_map; - -typedef struct ns_dev { - int index; /* Card ID to the device driver */ - int sram_size; /* In k x 32bit words. 32 or 128 */ - void __iomem *membase; /* Card's memory base address */ - unsigned long max_pcr; - int rct_size; /* Number of entries */ - int vpibits; - int vcibits; - struct pci_dev *pcidev; - struct idr idr; - struct atm_dev *atmdev; - tsq_info tsq; - rsq_info rsq; - scq_info *scq0, *scq1, *scq2; /* VBR SCQs */ - skb_pool sbpool; /* Small buffers */ - skb_pool lbpool; /* Large buffers */ - skb_pool hbpool; /* Pre-allocated huge buffers */ - skb_pool iovpool; /* iovector buffers */ - volatile int efbie; /* Empty free buf. queue int. enabled */ - volatile u32 tst_addr; /* SRAM address of the TST in use */ - volatile int tst_free_entries; - vc_map vcmap[NS_MAX_RCTSIZE]; - vc_map *tste2vc[NS_TST_NUM_ENTRIES]; - vc_map *scd2vc[NS_FRSCD_NUM]; - buf_nr sbnr; - buf_nr lbnr; - buf_nr hbnr; - buf_nr iovnr; - int sbfqc; - int lbfqc; - struct sk_buff *sm_handle; - u32 sm_addr; - struct sk_buff *lg_handle; - u32 lg_addr; - struct sk_buff *rcbuf; /* Current raw cell buffer */ - struct ns_rcqe *rawcell; - u32 rawch; /* Raw cell queue head */ - unsigned intcnt; /* Interrupt counter */ - spinlock_t int_lock; /* Interrupt lock */ - spinlock_t res_lock; /* Card resource lock */ -} ns_dev; - - /* NOTE: Each tste2vc entry relates a given TST entry to the corresponding - CBR vc. If the entry is not allocated, it must be NULL. - - There are two TSTs so the driver can modify them on the fly - without stopping the transmission. - - scd2vc allows us to find out unused fixed rate SCDs, because - they must have a NULL pointer here. */ - -#endif /* _LINUX_NICSTAR_H_ */ diff --git a/drivers/atm/suni.h b/drivers/atm/suni.h deleted file mode 100644 index d28a50d47d8b..000000000000 --- a/drivers/atm/suni.h +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * drivers/atm/suni.h - S/UNI PHY driver - */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - -#ifndef DRIVER_ATM_SUNI_H -#define DRIVER_ATM_SUNI_H - -#include -#include -#include - -/* SUNI registers */ - -#define SUNI_MRI 0x00 /* Master Reset and Identity / Load - Meter */ -#define SUNI_MC 0x01 /* Master Configuration */ -#define SUNI_MIS 0x02 /* Master Interrupt Status */ - /* no 0x03 */ -#define SUNI_MCM 0x04 /* Master Clock Monitor */ -#define SUNI_MCT 0x05 /* Master Control */ -#define SUNI_CSCS 0x06 /* Clock Synthesis Control and Status */ -#define SUNI_CRCS 0x07 /* Clock Recovery Control and Status */ - /* 0x08-0x0F reserved */ -#define SUNI_RSOP_CIE 0x10 /* RSOP Control/Interrupt Enable */ -#define SUNI_RSOP_SIS 0x11 /* RSOP Status/Interrupt Status */ -#define SUNI_RSOP_SBL 0x12 /* RSOP Section BIP-8 LSB */ -#define SUNI_RSOP_SBM 0x13 /* RSOP Section BIP-8 MSB */ -#define SUNI_TSOP_CTRL 0x14 /* TSOP Control */ -#define SUNI_TSOP_DIAG 0x15 /* TSOP Diagnostic */ - /* 0x16-0x17 reserved */ -#define SUNI_RLOP_CS 0x18 /* RLOP Control/Status */ -#define SUNI_RLOP_IES 0x19 /* RLOP Interrupt Enable/Status */ -#define SUNI_RLOP_LBL 0x1A /* RLOP Line BIP-8/24 LSB */ -#define SUNI_RLOP_LB 0x1B /* RLOP Line BIP-8/24 */ -#define SUNI_RLOP_LBM 0x1C /* RLOP Line BIP-8/24 MSB */ -#define SUNI_RLOP_LFL 0x1D /* RLOP Line FEBE LSB */ -#define SUNI_RLOP_LF 0x1E /* RLOP Line FEBE */ -#define SUNI_RLOP_LFM 0x1F /* RLOP Line FEBE MSB */ -#define SUNI_TLOP_CTRL 0x20 /* TLOP Control */ -#define SUNI_TLOP_DIAG 0x21 /* TLOP Diagnostic */ - /* 0x22-0x27 reserved */ -#define SUNI_SSTB_CTRL 0x28 -#define SUNI_RPOP_SC 0x30 /* RPOP Status/Control */ -#define SUNI_RPOP_IS 0x31 /* RPOP Interrupt Status */ - /* 0x32 reserved */ -#define SUNI_RPOP_IE 0x33 /* RPOP Interrupt Enable */ - /* 0x34-0x36 reserved */ -#define SUNI_RPOP_PSL 0x37 /* RPOP Path Signal Label */ -#define SUNI_RPOP_PBL 0x38 /* RPOP Path BIP-8 LSB */ -#define SUNI_RPOP_PBM 0x39 /* RPOP Path BIP-8 MSB */ -#define SUNI_RPOP_PFL 0x3A /* RPOP Path FEBE LSB */ -#define SUNI_RPOP_PFM 0x3B /* RPOP Path FEBE MSB */ - /* 0x3C reserved */ -#define SUNI_RPOP_PBC 0x3D /* RPOP Path BIP-8 Configuration */ -#define SUNI_RPOP_RC 0x3D /* RPOP Ring Control (PM5355) */ - /* 0x3E-0x3F reserved */ -#define SUNI_TPOP_CD 0x40 /* TPOP Control/Diagnostic */ -#define SUNI_TPOP_PC 0x41 /* TPOP Pointer Control */ - /* 0x42-0x44 reserved */ -#define SUNI_TPOP_APL 0x45 /* TPOP Arbitrary Pointer LSB */ -#define SUNI_TPOP_APM 0x46 /* TPOP Arbitrary Pointer MSB */ - /* 0x47 reserved */ -#define SUNI_TPOP_PSL 0x48 /* TPOP Path Signal Label */ -#define SUNI_TPOP_PS 0x49 /* TPOP Path Status */ - /* 0x4A-0x4F reserved */ -#define SUNI_RACP_CS 0x50 /* RACP Control/Status */ -#define SUNI_RACP_IES 0x51 /* RACP Interrupt Enable/Status */ -#define SUNI_RACP_MHP 0x52 /* RACP Match Header Pattern */ -#define SUNI_RACP_MHM 0x53 /* RACP Match Header Mask */ -#define SUNI_RACP_CHEC 0x54 /* RACP Correctable HCS Error Count */ -#define SUNI_RACP_UHEC 0x55 /* RACP Uncorrectable HCS Err Count */ -#define SUNI_RACP_RCCL 0x56 /* RACP Receive Cell Counter LSB */ -#define SUNI_RACP_RCC 0x57 /* RACP Receive Cell Counter */ -#define SUNI_RACP_RCCM 0x58 /* RACP Receive Cell Counter MSB */ -#define SUNI_RACP_CFG 0x59 /* RACP Configuration */ - /* 0x5A-0x5F reserved */ -#define SUNI_TACP_CS 0x60 /* TACP Control/Status */ -#define SUNI_TACP_IUCHP 0x61 /* TACP Idle/Unassigned Cell Hdr Pat */ -#define SUNI_TACP_IUCPOP 0x62 /* TACP Idle/Unassigned Cell Payload - Octet Pattern */ -#define SUNI_TACP_FIFO 0x63 /* TACP FIFO Configuration */ -#define SUNI_TACP_TCCL 0x64 /* TACP Transmit Cell Counter LSB */ -#define SUNI_TACP_TCC 0x65 /* TACP Transmit Cell Counter */ -#define SUNI_TACP_TCCM 0x66 /* TACP Transmit Cell Counter MSB */ -#define SUNI_TACP_CFG 0x67 /* TACP Configuration */ -#define SUNI_SPTB_CTRL 0x68 /* SPTB Control */ - /* 0x69-0x7F reserved */ -#define SUNI_MT 0x80 /* Master Test */ - /* 0x81-0xFF reserved */ - -/* SUNI register values */ - - -/* MRI is reg 0 */ -#define SUNI_MRI_ID 0x0f /* R, SUNI revision number */ -#define SUNI_MRI_ID_SHIFT 0 -#define SUNI_MRI_TYPE 0x70 /* R, SUNI type (lite is 011) */ -#define SUNI_MRI_TYPE_SHIFT 4 -#define SUNI_MRI_TYPE_PM5346 0x3 /* S/UNI 155 LITE */ -#define SUNI_MRI_TYPE_PM5347 0x4 /* S/UNI 155 PLUS */ -#define SUNI_MRI_TYPE_PM5350 0x7 /* S/UNI 155 ULTRA */ -#define SUNI_MRI_TYPE_PM5355 0x1 /* S/UNI 622 */ -#define SUNI_MRI_RESET 0x80 /* RW, reset & power down chip - 0: normal operation - 1: reset & low power */ - -/* MCM is reg 0x4 */ -#define SUNI_MCM_LLE 0x20 /* line loopback (PM5355) */ -#define SUNI_MCM_DLE 0x10 /* diagnostic loopback (PM5355) */ - -/* MCT is reg 5 */ -#define SUNI_MCT_LOOPT 0x01 /* RW, timing source, 0: from - TRCLK+/- */ -#define SUNI_MCT_DLE 0x02 /* RW, diagnostic loopback */ -#define SUNI_MCT_LLE 0x04 /* RW, line loopback */ -#define SUNI_MCT_FIXPTR 0x20 /* RW, disable transmit payload pointer - adjustments - 0: payload ptr controlled by TPOP - ptr control reg - 1: payload pointer fixed at 522 */ -#define SUNI_MCT_LCDV 0x40 /* R, loss of cell delineation */ -#define SUNI_MCT_LCDE 0x80 /* RW, loss of cell delineation - interrupt (1: on) */ -/* RSOP_CIE is reg 0x10 */ -#define SUNI_RSOP_CIE_OOFE 0x01 /* RW, enable interrupt on frame alarm - state change */ -#define SUNI_RSOP_CIE_LOFE 0x02 /* RW, enable interrupt on loss of - frame state change */ -#define SUNI_RSOP_CIE_LOSE 0x04 /* RW, enable interrupt on loss of - signal state change */ -#define SUNI_RSOP_CIE_BIPEE 0x08 /* RW, enable interrupt on section - BIP-8 error (B1) */ -#define SUNI_RSOP_CIE_FOOF 0x20 /* W, force RSOP out of frame at next - boundary */ -#define SUNI_RSOP_CIE_DDS 0x40 /* RW, disable scrambling */ - -/* RSOP_SIS is reg 0x11 */ -#define SUNI_RSOP_SIS_OOFV 0x01 /* R, out of frame */ -#define SUNI_RSOP_SIS_LOFV 0x02 /* R, loss of frame */ -#define SUNI_RSOP_SIS_LOSV 0x04 /* R, loss of signal */ -#define SUNI_RSOP_SIS_OOFI 0x08 /* R, out of frame interrupt */ -#define SUNI_RSOP_SIS_LOFI 0x10 /* R, loss of frame interrupt */ -#define SUNI_RSOP_SIS_LOSI 0x20 /* R, loss of signal interrupt */ -#define SUNI_RSOP_SIS_BIPEI 0x40 /* R, section BIP-8 interrupt */ - -/* TSOP_CTRL is reg 0x14 */ -#define SUNI_TSOP_CTRL_LAIS 0x01 /* insert alarm indication signal */ -#define SUNI_TSOP_CTRL_DS 0x40 /* disable scrambling */ - -/* TSOP_DIAG is reg 0x15 */ -#define SUNI_TSOP_DIAG_DFP 0x01 /* insert single bit error cont. */ -#define SUNI_TSOP_DIAG_DBIP8 0x02 /* insert section BIP err (cont) */ -#define SUNI_TSOP_DIAG_DLOS 0x04 /* set line to zero (loss of signal) */ - -/* TLOP_DIAG is reg 0x21 */ -#define SUNI_TLOP_DIAG_DBIP 0x01 /* insert line BIP err (continuously) */ - -/* SSTB_CTRL is reg 0x28 */ -#define SUNI_SSTB_CTRL_LEN16 0x01 /* path trace message length bit */ - -/* RPOP_RC is reg 0x3D (PM5355) */ -#define SUNI_RPOP_RC_ENSS 0x40 /* enable size bit */ - -/* TPOP_DIAG is reg 0x40 */ -#define SUNI_TPOP_DIAG_PAIS 0x01 /* insert STS path alarm ind (cont) */ -#define SUNI_TPOP_DIAG_DB3 0x02 /* insert path BIP err (continuously) */ - -/* TPOP_APM is reg 0x46 */ -#define SUNI_TPOP_APM_APTR 0x03 /* RW, arbitrary pointer, upper 2 - bits */ -#define SUNI_TPOP_APM_APTR_SHIFT 0 -#define SUNI_TPOP_APM_S 0x0c /* RW, "unused" bits of payload - pointer */ -#define SUNI_TPOP_APM_S_SHIFT 2 -#define SUNI_TPOP_APM_NDF 0xf0 /* RW, NDF bits */ -#define SUNI_TPOP_APM_NDF_SHIFT 4 - -#define SUNI_TPOP_S_SONET 0 /* set S bits to 00 */ -#define SUNI_TPOP_S_SDH 2 /* set S bits to 10 */ - -/* RACP_IES is reg 0x51 */ -#define SUNI_RACP_IES_FOVRI 0x02 /* R, FIFO overrun */ -#define SUNI_RACP_IES_UHCSI 0x04 /* R, uncorrectable HCS error */ -#define SUNI_RACP_IES_CHCSI 0x08 /* R, correctable HCS error */ -#define SUNI_RACP_IES_OOCDI 0x10 /* R, change of cell delineation - state */ -#define SUNI_RACP_IES_FIFOE 0x20 /* RW, enable FIFO overrun interrupt */ -#define SUNI_RACP_IES_HCSE 0x40 /* RW, enable HCS error interrupt */ -#define SUNI_RACP_IES_OOCDE 0x80 /* RW, enable cell delineation state - change interrupt */ - -/* TACP_CS is reg 0x60 */ -#define SUNI_TACP_CS_FIFORST 0x01 /* RW, reset transmit FIFO (sticky) */ -#define SUNI_TACP_CS_DSCR 0x02 /* RW, disable payload scrambling */ -#define SUNI_TACP_CS_HCAADD 0x04 /* RW, add coset polynomial to HCS */ -#define SUNI_TACP_CS_DHCS 0x10 /* RW, insert HCS errors */ -#define SUNI_TACP_CS_FOVRI 0x20 /* R, FIFO overrun */ -#define SUNI_TACP_CS_TSOCI 0x40 /* R, TSOC input high */ -#define SUNI_TACP_CS_FIFOE 0x80 /* RW, enable FIFO overrun interrupt */ - -/* TACP_IUCHP is reg 0x61 */ -#define SUNI_TACP_IUCHP_CLP 0x01 /* RW, 8th bit of 4th octet of i/u - pattern */ -#define SUNI_TACP_IUCHP_PTI 0x0e /* RW, 5th-7th bits of 4th octet of i/u - pattern */ -#define SUNI_TACP_IUCHP_PTI_SHIFT 1 -#define SUNI_TACP_IUCHP_GFC 0xf0 /* RW, 1st-4th bits of 1st octet of i/u - pattern */ -#define SUNI_TACP_IUCHP_GFC_SHIFT 4 - -/* SPTB_CTRL is reg 0x68 */ -#define SUNI_SPTB_CTRL_LEN16 0x01 /* path trace message length */ - -/* MT is reg 0x80 */ -#define SUNI_MT_HIZIO 0x01 /* RW, all but data bus & MP interface - tri-state */ -#define SUNI_MT_HIZDATA 0x02 /* W, also tri-state data bus */ -#define SUNI_MT_IOTST 0x04 /* RW, enable test mode */ -#define SUNI_MT_DBCTRL 0x08 /* W, control data bus by CSB pin */ -#define SUNI_MT_PMCTST 0x10 /* W, PMC test mode */ -#define SUNI_MT_DS27_53 0x80 /* RW, select between 8- or 16- bit */ - - -#define SUNI_IDLE_PATTERN 0x6a /* idle pattern */ - - -#ifdef __KERNEL__ -struct suni_priv { - struct k_sonet_stats sonet_stats; /* link diagnostics */ - int loop_mode; /* loopback mode */ - int type; /* phy type */ - struct atm_dev *dev; /* device back-pointer */ - struct suni_priv *next; /* next SUNI */ -}; - -int suni_init(struct atm_dev *dev); -#endif - -#endif diff --git a/drivers/atm/tonga.h b/drivers/atm/tonga.h deleted file mode 100644 index 771b3f95246c..000000000000 --- a/drivers/atm/tonga.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/tonga.h - Efficient Networks Tonga (PCI bridge) declarations */ - -/* Written 1995 by Werner Almesberger, EPFL LRC */ - - -#ifndef DRIVER_ATM_TONGA_H -#define DRIVER_ATM_TONGA_H - -#define PCI_TONGA_CTRL 0x60 /* control register */ - -#define END_SWAP_DMA 0x80 /* endian swap on DMA */ -#define END_SWAP_BYTE 0x40 /* endian swap on slave byte accesses */ -#define END_SWAP_WORD 0x20 /* endian swap on slave word accesses */ -#define SEPROM_MAGIC 0x0c /* obscure required pattern (ASIC only) */ -#define SEPROM_DATA 0x02 /* serial EEPROM data (ASIC only) */ -#define SEPROM_CLK 0x01 /* serial EEPROM clock (ASIC only) */ - -#define SEPROM_ESI_BASE 64 /* start of ESI in serial EEPROM */ - -#endif diff --git a/drivers/atm/zeprom.h b/drivers/atm/zeprom.h deleted file mode 100644 index 8e8819a3840d..000000000000 --- a/drivers/atm/zeprom.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* drivers/atm/zeprom.h - ZeitNet ZN122x EEPROM (NM93C46) declarations */ - -/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ - - -#ifndef DRIVER_ATM_ZEPROM_H -#define DRIVER_ATM_ZEPROM_H - -/* Different versions use different control registers */ - -#define ZEPROM_V1_REG PCI_VENDOR_ID /* PCI register */ -#define ZEPROM_V2_REG 0x40 - -/* Bits in control register */ - -#define ZEPROM_SK 0x80000000 /* strobe (probably on raising edge) */ -#define ZEPROM_CS 0x40000000 /* Chip Select */ -#define ZEPROM_DI 0x20000000 /* Data Input */ -#define ZEPROM_DO 0x10000000 /* Data Output */ - -#define ZEPROM_SIZE 32 /* 32 bytes */ -#define ZEPROM_V1_ESI_OFF 24 /* ESI offset in EEPROM (V1) */ -#define ZEPROM_V2_ESI_OFF 4 /* ESI offset in EEPROM (V2) */ - -#define ZEPROM_CMD_LEN 3 /* commands are three bits */ -#define ZEPROM_ADDR_LEN 6 /* addresses are six bits */ - -/* Commands (3 bits) */ - -#define ZEPROM_CMD_READ 6 - -/* No other commands are needed. */ - -#endif diff --git a/net/atm/lec.h b/net/atm/lec.h deleted file mode 100644 index ec85709bf818..000000000000 --- a/net/atm/lec.h +++ /dev/null @@ -1,155 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Lan Emulation client header file - * - * Marko Kiiskila - */ - -#ifndef _LEC_H_ -#define _LEC_H_ - -#include -#include -#include - -#define LEC_HEADER_LEN 16 - -struct lecdatahdr_8023 { - __be16 le_header; - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; - __be16 h_type; -}; - -struct lecdatahdr_8025 { - __be16 le_header; - unsigned char ac_pad; - unsigned char fc; - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; -}; - -#define LEC_MINIMUM_8023_SIZE 62 -#define LEC_MINIMUM_8025_SIZE 16 - -/* - * Operations that LANE2 capable device can do. Two first functions - * are used to make the device do things. See spec 3.1.3 and 3.1.4. - * - * The third function is intended for the MPOA component sitting on - * top of the LANE device. The MPOA component assigns it's own function - * to (*associate_indicator)() and the LANE device will use that - * function to tell about TLVs it sees floating through. - * - */ -struct lane2_ops { - int (*resolve) (struct net_device *dev, const u8 *dst_mac, int force, - u8 **tlvs, u32 *sizeoftlvs); - int (*associate_req) (struct net_device *dev, const u8 *lan_dst, - const u8 *tlvs, u32 sizeoftlvs); - void (*associate_indicator) (struct net_device *dev, const u8 *mac_addr, - const u8 *tlvs, u32 sizeoftlvs); -}; - -/* - * ATM LAN Emulation supports both LLC & Dix Ethernet EtherType - * frames. - * - * 1. Dix Ethernet EtherType frames encoded by placing EtherType - * field in h_type field. Data follows immediately after header. - * 2. LLC Data frames whose total length, including LLC field and data, - * but not padding required to meet the minimum data frame length, - * is less than ETH_P_802_3_MIN MUST be encoded by placing that length - * in the h_type field. The LLC field follows header immediately. - * 3. LLC data frames longer than this maximum MUST be encoded by placing - * the value 0 in the h_type field. - * - */ - -/* Hash table size */ -#define LEC_ARP_TABLE_SIZE 16 - -struct lec_priv { - unsigned short lecid; /* Lecid of this client */ - struct hlist_head lec_arp_empty_ones; - /* Used for storing VCC's that don't have a MAC address attached yet */ - struct hlist_head lec_arp_tables[LEC_ARP_TABLE_SIZE]; - /* Actual LE ARP table */ - struct hlist_head lec_no_forward; - /* - * Used for storing VCC's (and forward packets from) which are to - * age out by not using them to forward packets. - * This is because to some LE clients there will be 2 VCCs. Only - * one of them gets used. - */ - struct hlist_head mcast_fwds; - /* - * With LANEv2 it is possible that BUS (or a special multicast server) - * establishes multiple Multicast Forward VCCs to us. This list - * collects all those VCCs. LANEv1 client has only one item in this - * list. These entries are not aged out. - */ - spinlock_t lec_arp_lock; - struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ - struct atm_vcc __rcu *lecd; - struct delayed_work lec_arp_work; /* C10 */ - unsigned int maximum_unknown_frame_count; - /* - * Within the period of time defined by this variable, the client will send - * no more than C10 frames to BUS for a given unicast destination. (C11) - */ - unsigned long max_unknown_frame_time; - /* - * If no traffic has been sent in this vcc for this period of time, - * vcc will be torn down (C12) - */ - unsigned long vcc_timeout_period; - /* - * An LE Client MUST not retry an LE_ARP_REQUEST for a - * given frame's LAN Destination more than maximum retry count times, - * after the first LEC_ARP_REQUEST (C13) - */ - unsigned short max_retry_count; - /* - * Max time the client will maintain an entry in its arp cache in - * absence of a verification of that relationship (C17) - */ - unsigned long aging_time; - /* - * Max time the client will maintain an entry in cache when - * topology change flag is true (C18) - */ - unsigned long forward_delay_time; /* Topology change flag (C19) */ - int topology_change; - /* - * Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE - * cycle to take (C20) - */ - unsigned long arp_response_time; - /* - * Time limit ot wait to receive an LE_FLUSH_RESPONSE after the - * LE_FLUSH_REQUEST has been sent before taking recover action. (C21) - */ - unsigned long flush_timeout; - /* The time since sending a frame to the bus after which the - * LE Client may assume that the frame has been either discarded or - * delivered to the recipient (C22) - */ - unsigned long path_switching_delay; - - u8 *tlvs; /* LANE2: TLVs are new */ - u32 sizeoftlvs; /* The size of the tlv array in bytes */ - int lane_version; /* LANE2 */ - int itfnum; /* e.g. 2 for lec2, 5 for lec5 */ - struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */ - int is_proxy; /* bridge between ATM and Ethernet */ -}; - -struct lec_vcc_priv { - void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb); - int xoff; -}; - -#define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back)) - -#endif /* _LEC_H_ */ diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h deleted file mode 100644 index 39115fe074c4..000000000000 --- a/net/atm/lec_arpc.h +++ /dev/null @@ -1,97 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Lec arp cache - * - * Marko Kiiskila - */ -#ifndef _LEC_ARP_H_ -#define _LEC_ARP_H_ -#include -#include -#include -#include - -struct lec_arp_table { - struct hlist_node next; /* Linked entry list */ - unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */ - unsigned char mac_addr[ETH_ALEN]; /* Mac address */ - int is_rdesc; /* Mac address is a route descriptor */ - struct atm_vcc *vcc; /* Vcc this entry is attached */ - struct atm_vcc *recv_vcc; /* Vcc we receive data from */ - - void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb); - /* Push that leads to daemon */ - - void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb); - /* Push that leads to daemon */ - - unsigned long last_used; /* For expiry */ - unsigned long timestamp; /* Used for various timestamping things: - * 1. FLUSH started - * (status=ESI_FLUSH_PENDING) - * 2. Counting to - * max_unknown_frame_time - * (status=ESI_ARP_PENDING|| - * status=ESI_VC_PENDING) - */ - unsigned char no_tries; /* No of times arp retry has been tried */ - unsigned char status; /* Status of this entry */ - unsigned short flags; /* Flags for this entry */ - unsigned short packets_flooded; /* Data packets flooded */ - unsigned long flush_tran_id; /* Transaction id in flush protocol */ - struct timer_list timer; /* Arping timer */ - struct lec_priv *priv; /* Pointer back */ - u8 *tlvs; - u32 sizeoftlvs; /* - * LANE2: Each MAC address can have TLVs - * associated with it. sizeoftlvs tells - * the length of the tlvs array - */ - struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ - refcount_t usage; /* usage count */ -}; - -/* - * LANE2: Template tlv struct for accessing - * the tlvs in the lec_arp_table->tlvs array - */ -struct tlv { - u32 type; - u8 length; - u8 value[255]; -}; - -/* Status fields */ -#define ESI_UNKNOWN 0 /* - * Next packet sent to this mac address - * causes ARP-request to be sent - */ -#define ESI_ARP_PENDING 1 /* - * There is no ATM address associated with this - * 48-bit address. The LE-ARP protocol is in - * progress. - */ -#define ESI_VC_PENDING 2 /* - * There is a valid ATM address associated with - * this 48-bit address but there is no VC set - * up to that ATM address. The signaling - * protocol is in process. - */ -#define ESI_FLUSH_PENDING 4 /* - * The LEC has been notified of the FLUSH_START - * status and it is assumed that the flush - * protocol is in process. - */ -#define ESI_FORWARD_DIRECT 5 /* - * Either the Path Switching Delay (C22) has - * elapsed or the LEC has notified the Mapping - * that the flush protocol has completed. In - * either case, it is safe to forward packets - * to this address via the data direct VC. - */ - -/* Flag values */ -#define LEC_REMOTE_FLAG 0x0001 -#define LEC_PERMANENT_FLAG 0x0002 - -#endif /* _LEC_ARP_H_ */ diff --git a/net/atm/mpc.h b/net/atm/mpc.h deleted file mode 100644 index 454abd07651a..000000000000 --- a/net/atm/mpc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _MPC_H_ -#define _MPC_H_ - -#include -#include -#include -#include -#include -#include "mpoa_caches.h" - -/* kernel -> mpc-daemon */ -int msg_to_mpoad(struct k_message *msg, struct mpoa_client *mpc); - -struct mpoa_client { - struct mpoa_client *next; - struct net_device *dev; /* lec in question */ - int dev_num; /* e.g. 2 for lec2 */ - - struct atm_vcc *mpoad_vcc; /* control channel to mpoad */ - uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */ - uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */ - - rwlock_t ingress_lock; - const struct in_cache_ops *in_ops; /* ingress cache operations */ - in_cache_entry *in_cache; /* the ingress cache of this MPC */ - - rwlock_t egress_lock; - const struct eg_cache_ops *eg_ops; /* egress cache operations */ - eg_cache_entry *eg_cache; /* the egress cache of this MPC */ - - uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */ - int number_of_mps_macs; /* number of the above MAC addresses */ - struct mpc_parameters parameters; /* parameters for this client */ - - const struct net_device_ops *old_ops; - struct net_device_ops new_ops; -}; - - -struct atm_mpoa_qos { - struct atm_mpoa_qos *next; - __be32 ipaddr; - struct atm_qos qos; -}; - - -/* MPOA QoS operations */ -struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos); -struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip); -int atm_mpoa_delete_qos(struct atm_mpoa_qos *qos); - -/* Display QoS entries. This is for the procfs */ -struct seq_file; -void atm_mpoa_disp_qos(struct seq_file *m); - -#ifdef CONFIG_PROC_FS -int mpc_proc_init(void); -void mpc_proc_clean(void); -#else -#define mpc_proc_init() (0) -#define mpc_proc_clean() do { } while(0) -#endif - -#endif /* _MPC_H_ */ diff --git a/net/atm/mpoa_caches.h b/net/atm/mpoa_caches.h deleted file mode 100644 index 464c4c7f8d1f..000000000000 --- a/net/atm/mpoa_caches.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef MPOA_CACHES_H -#define MPOA_CACHES_H - -#include -#include -#include -#include -#include -#include -#include - -struct mpoa_client; - -void atm_mpoa_init_cache(struct mpoa_client *mpc); - -typedef struct in_cache_entry { - struct in_cache_entry *next; - struct in_cache_entry *prev; - time64_t time; - time64_t reply_wait; - time64_t hold_down; - uint32_t packets_fwded; - uint16_t entry_state; - uint32_t retry_time; - uint32_t refresh_time; - uint32_t count; - struct atm_vcc *shortcut; - uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; - struct in_ctrl_info ctrl_info; - refcount_t use; -} in_cache_entry; - -struct in_cache_ops{ - in_cache_entry *(*add_entry)(__be32 dst_ip, - struct mpoa_client *client); - in_cache_entry *(*get)(__be32 dst_ip, struct mpoa_client *client); - in_cache_entry *(*get_with_mask)(__be32 dst_ip, - struct mpoa_client *client, - __be32 mask); - in_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, - struct mpoa_client *client); - void (*put)(in_cache_entry *entry); - void (*remove_entry)(in_cache_entry *delEntry, - struct mpoa_client *client ); - int (*cache_hit)(in_cache_entry *entry, - struct mpoa_client *client); - void (*clear_count)(struct mpoa_client *client); - void (*check_resolving)(struct mpoa_client *client); - void (*refresh)(struct mpoa_client *client); - void (*destroy_cache)(struct mpoa_client *mpc); -}; - -typedef struct eg_cache_entry{ - struct eg_cache_entry *next; - struct eg_cache_entry *prev; - time64_t time; - uint8_t MPS_ctrl_ATM_addr[ATM_ESA_LEN]; - struct atm_vcc *shortcut; - uint32_t packets_rcvd; - uint16_t entry_state; - __be32 latest_ip_addr; /* The src IP address of the last packet */ - struct eg_ctrl_info ctrl_info; - refcount_t use; -} eg_cache_entry; - -struct eg_cache_ops{ - eg_cache_entry *(*add_entry)(struct k_message *msg, struct mpoa_client *client); - eg_cache_entry *(*get_by_cache_id)(__be32 cache_id, struct mpoa_client *client); - eg_cache_entry *(*get_by_tag)(__be32 cache_id, struct mpoa_client *client); - eg_cache_entry *(*get_by_vcc)(struct atm_vcc *vcc, struct mpoa_client *client); - eg_cache_entry *(*get_by_src_ip)(__be32 ipaddr, struct mpoa_client *client); - void (*put)(eg_cache_entry *entry); - void (*remove_entry)(eg_cache_entry *entry, struct mpoa_client *client); - void (*update)(eg_cache_entry *entry, uint16_t holding_time); - void (*clear_expired)(struct mpoa_client *client); - void (*destroy_cache)(struct mpoa_client *mpc); -}; - - -/* Ingress cache entry states */ - -#define INGRESS_REFRESHING 3 -#define INGRESS_RESOLVED 2 -#define INGRESS_RESOLVING 1 -#define INGRESS_INVALID 0 - -/* VCC states */ - -#define OPEN 1 -#define CLOSED 0 - -/* Egress cache entry states */ - -#define EGRESS_RESOLVED 2 -#define EGRESS_PURGE 1 -#define EGRESS_INVALID 0 - -#endif diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 361a9b84451e..bed1b1d9b282 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -855,7 +855,6 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_fdb_entry *br_fdb_find_rcu(struct net_bridge *br, const unsigned char *addr, __u16 vid); -int br_fdb_test_addr(struct net_device *dev, unsigned char *addr); int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count, unsigned long off); int br_fdb_add_local(struct net_bridge *br, struct net_bridge_port *source, @@ -2065,9 +2064,6 @@ void br_stp_port_timer_init(struct net_bridge_port *p); unsigned long br_timer_value(const struct timer_list *timer); /* br.c */ -#if IS_ENABLED(CONFIG_ATM_LANE) -extern int (*br_fdb_test_addr_hook)(struct net_device *dev, unsigned char *addr); -#endif /* br_mrp.c */ #if IS_ENABLED(CONFIG_BRIDGE_MRP) diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c deleted file mode 100644 index c8d00537d236..000000000000 --- a/drivers/atm/adummy.c +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * adummy.c: a dummy ATM driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* version definition */ - -#define DRV_VERSION "1.0" - -#define DEV_LABEL "adummy" - -#define ADUMMY_DEV(dev) ((struct adummy_dev *) (dev)->dev_data) - -struct adummy_dev { - struct atm_dev *atm_dev; - - struct list_head entry; -}; - -/* globals */ - -static LIST_HEAD(adummy_devs); - -static ssize_t __set_signal(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev); - int signal; - - if (sscanf(buf, "%d", &signal) == 1) { - - if (signal < ATM_PHY_SIG_LOST || signal > ATM_PHY_SIG_FOUND) - signal = ATM_PHY_SIG_UNKNOWN; - - atm_dev_signal_change(atm_dev, signal); - return 1; - } - return -EINVAL; -} - -static ssize_t __show_signal(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct atm_dev *atm_dev = container_of(dev, struct atm_dev, class_dev); - return sprintf(buf, "%d\n", atm_dev->signal); -} -static DEVICE_ATTR(signal, 0644, __show_signal, __set_signal); - -static struct attribute *adummy_attrs[] = { - &dev_attr_signal.attr, - NULL -}; - -static const struct attribute_group adummy_group_attrs = { - .name = NULL, /* We want them in dev's root folder */ - .attrs = adummy_attrs -}; - -static int __init -adummy_start(struct atm_dev *dev) -{ - dev->ci_range.vpi_bits = 4; - dev->ci_range.vci_bits = 12; - - return 0; -} - -static int -adummy_open(struct atm_vcc *vcc) -{ - short vpi = vcc->vpi; - int vci = vcc->vci; - - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) - return 0; - - set_bit(ATM_VF_ADDR, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - return 0; -} - -static void -adummy_close(struct atm_vcc *vcc) -{ - clear_bit(ATM_VF_READY, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); -} - -static int -adummy_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx); - - return 0; -} - -static int -adummy_proc_read(struct atm_dev *dev, loff_t *pos, char *page) -{ - int left = *pos; - - if (!left--) - return sprintf(page, "version %s\n", DRV_VERSION); - - return 0; -} - -static const struct atmdev_ops adummy_ops = -{ - .open = adummy_open, - .close = adummy_close, - .send = adummy_send, - .proc_read = adummy_proc_read, - .owner = THIS_MODULE -}; - -static int __init adummy_init(void) -{ - struct atm_dev *atm_dev; - struct adummy_dev *adummy_dev; - int err = 0; - - printk(KERN_ERR "adummy: version %s\n", DRV_VERSION); - - adummy_dev = kzalloc_obj(struct adummy_dev); - if (!adummy_dev) { - printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n"); - err = -ENOMEM; - goto out; - } - atm_dev = atm_dev_register(DEV_LABEL, NULL, &adummy_ops, -1, NULL); - if (!atm_dev) { - printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n"); - err = -ENODEV; - goto out_kfree; - } - - adummy_dev->atm_dev = atm_dev; - atm_dev->dev_data = adummy_dev; - - if (sysfs_create_group(&atm_dev->class_dev.kobj, &adummy_group_attrs)) - dev_err(&atm_dev->class_dev, "Could not register attrs for adummy\n"); - - if (adummy_start(atm_dev)) { - printk(KERN_ERR DEV_LABEL ": adummy_start() failed\n"); - err = -ENODEV; - goto out_unregister; - } - - list_add(&adummy_dev->entry, &adummy_devs); -out: - return err; - -out_unregister: - atm_dev_deregister(atm_dev); -out_kfree: - kfree(adummy_dev); - goto out; -} - -static void __exit adummy_cleanup(void) -{ - struct adummy_dev *adummy_dev, *next; - - list_for_each_entry_safe(adummy_dev, next, &adummy_devs, entry) { - atm_dev_deregister(adummy_dev->atm_dev); - kfree(adummy_dev); - } -} - -module_init(adummy_init); -module_exit(adummy_cleanup); - -MODULE_AUTHOR("chas williams "); -MODULE_DESCRIPTION("dummy ATM driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c deleted file mode 100644 index 96719851ae2a..000000000000 --- a/drivers/atm/atmtcp.c +++ /dev/null @@ -1,513 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ - -/* Written 1997-2000 by Werner Almesberger, EPFL LRC/ICA */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -extern int atm_init_aal5(struct atm_vcc *vcc); /* "raw" AAL5 transport */ - - -#define PRIV(dev) ((struct atmtcp_dev_data *) ((dev)->dev_data)) - - -struct atmtcp_dev_data { - struct atm_vcc *vcc; /* control VCC; NULL if detached */ - int persist; /* non-zero if persistent */ -}; - - -#define DEV_LABEL "atmtcp" - -#define MAX_VPI_BITS 8 /* simplifies life */ -#define MAX_VCI_BITS 16 - - -/* - * Hairy code ahead: the control VCC may be closed while we're still - * waiting for an answer, so we need to re-validate out_vcc every once - * in a while. - */ - - -static int atmtcp_send_control(struct atm_vcc *vcc,int type, - const struct atmtcp_control *msg,int flag) -{ - DECLARE_WAITQUEUE(wait,current); - struct atm_vcc *out_vcc; - struct sk_buff *skb; - struct atmtcp_control *new_msg; - int old_test; - int error = 0; - - out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; - if (!out_vcc) return -EUNATCH; - skb = alloc_skb(sizeof(*msg),GFP_KERNEL); - if (!skb) return -ENOMEM; - mb(); - out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; - if (!out_vcc) { - dev_kfree_skb(skb); - return -EUNATCH; - } - atm_force_charge(out_vcc,skb->truesize); - new_msg = skb_put(skb, sizeof(*new_msg)); - *new_msg = *msg; - new_msg->hdr.length = ATMTCP_HDR_MAGIC; - new_msg->type = type; - memset(&new_msg->vcc,0,sizeof(atm_kptr_t)); - *(struct atm_vcc **) &new_msg->vcc = vcc; - old_test = test_bit(flag,&vcc->flags); - out_vcc->push(out_vcc,skb); - add_wait_queue(sk_sleep(sk_atm(vcc)), &wait); - while (test_bit(flag,&vcc->flags) == old_test) { - mb(); - out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL; - if (!out_vcc) { - error = -EUNATCH; - break; - } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(sk_sleep(sk_atm(vcc)), &wait); - return error; -} - - -static int atmtcp_recv_control(const struct atmtcp_control *msg) -{ - struct atm_vcc *vcc = *(struct atm_vcc **) &msg->vcc; - - vcc->vpi = msg->addr.sap_addr.vpi; - vcc->vci = msg->addr.sap_addr.vci; - vcc->qos = msg->qos; - sk_atm(vcc)->sk_err = -msg->result; - switch (msg->type) { - case ATMTCP_CTRL_OPEN: - change_bit(ATM_VF_READY,&vcc->flags); - break; - case ATMTCP_CTRL_CLOSE: - change_bit(ATM_VF_ADDR,&vcc->flags); - break; - default: - printk(KERN_ERR "atmtcp_recv_control: unknown type %d\n", - msg->type); - return -EINVAL; - } - wake_up(sk_sleep(sk_atm(vcc))); - return 0; -} - - -static void atmtcp_v_dev_close(struct atm_dev *dev) -{ - /* Nothing.... Isn't this simple :-) -- REW */ -} - - -static int atmtcp_v_open(struct atm_vcc *vcc) -{ - struct atmtcp_control msg; - int error; - short vpi = vcc->vpi; - int vci = vcc->vci; - - memset(&msg,0,sizeof(msg)); - msg.addr.sap_family = AF_ATMPVC; - msg.hdr.vpi = htons(vpi); - msg.addr.sap_addr.vpi = vpi; - msg.hdr.vci = htons(vci); - msg.addr.sap_addr.vci = vci; - if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) return 0; - msg.type = ATMTCP_CTRL_OPEN; - msg.qos = vcc->qos; - set_bit(ATM_VF_ADDR,&vcc->flags); - clear_bit(ATM_VF_READY,&vcc->flags); /* just in case ... */ - error = atmtcp_send_control(vcc,ATMTCP_CTRL_OPEN,&msg,ATM_VF_READY); - if (error) return error; - return -sk_atm(vcc)->sk_err; -} - - -static void atmtcp_v_close(struct atm_vcc *vcc) -{ - struct atmtcp_control msg; - - memset(&msg,0,sizeof(msg)); - msg.addr.sap_family = AF_ATMPVC; - msg.addr.sap_addr.vpi = vcc->vpi; - msg.addr.sap_addr.vci = vcc->vci; - clear_bit(ATM_VF_READY,&vcc->flags); - (void) atmtcp_send_control(vcc,ATMTCP_CTRL_CLOSE,&msg,ATM_VF_ADDR); -} - - -static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - struct atm_cirange ci; - struct atm_vcc *vcc; - struct sock *s; - int i; - - if (cmd != ATM_SETCIRANGE) return -ENOIOCTLCMD; - if (copy_from_user(&ci, arg,sizeof(ci))) return -EFAULT; - if (ci.vpi_bits == ATM_CI_MAX) ci.vpi_bits = MAX_VPI_BITS; - if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS; - if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 || - ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL; - read_lock(&vcc_sklist_lock); - for(i = 0; i < VCC_HTABLE_SIZE; ++i) { - struct hlist_head *head = &vcc_hash[i]; - - sk_for_each(s, head) { - vcc = atm_sk(s); - if (vcc->dev != dev) - continue; - if ((vcc->vpi >> ci.vpi_bits) || - (vcc->vci >> ci.vci_bits)) { - read_unlock(&vcc_sklist_lock); - return -EBUSY; - } - } - } - read_unlock(&vcc_sklist_lock); - dev->ci_range = ci; - return 0; -} - - -static int atmtcp_v_send(struct atm_vcc *vcc,struct sk_buff *skb) -{ - struct atmtcp_dev_data *dev_data; - struct atm_vcc *out_vcc=NULL; /* Initializer quietens GCC warning */ - struct sk_buff *new_skb; - struct atmtcp_hdr *hdr; - int size; - - if (vcc->qos.txtp.traffic_class == ATM_NONE) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return -EINVAL; - } - dev_data = PRIV(vcc->dev); - if (dev_data) out_vcc = dev_data->vcc; - if (!dev_data || !out_vcc) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - if (dev_data) return 0; - atomic_inc(&vcc->stats->tx_err); - return -ENOLINK; - } - size = skb->len+sizeof(struct atmtcp_hdr); - new_skb = atm_alloc_charge(out_vcc,size,GFP_ATOMIC); - if (!new_skb) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - atomic_inc(&vcc->stats->tx_err); - return -ENOBUFS; - } - hdr = skb_put(new_skb, sizeof(struct atmtcp_hdr)); - hdr->vpi = htons(vcc->vpi); - hdr->vci = htons(vcc->vci); - hdr->length = htonl(skb->len); - skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len); - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - out_vcc->push(out_vcc,new_skb); - atomic_inc(&vcc->stats->tx); - atomic_inc(&out_vcc->stats->rx); - return 0; -} - - -static int atmtcp_v_proc(struct atm_dev *dev,loff_t *pos,char *page) -{ - struct atmtcp_dev_data *dev_data = PRIV(dev); - - if (*pos) return 0; - if (!dev_data->persist) return sprintf(page,"ephemeral\n"); - return sprintf(page,"persistent, %sconnected\n", - dev_data->vcc ? "" : "dis"); -} - - -static void atmtcp_c_close(struct atm_vcc *vcc) -{ - struct atm_dev *atmtcp_dev; - struct atmtcp_dev_data *dev_data; - - atmtcp_dev = (struct atm_dev *) vcc->dev_data; - dev_data = PRIV(atmtcp_dev); - dev_data->vcc = NULL; - if (dev_data->persist) return; - atmtcp_dev->dev_data = NULL; - kfree(dev_data); - atm_dev_deregister(atmtcp_dev); - vcc->dev_data = NULL; - module_put(THIS_MODULE); -} - - -static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) -{ - struct hlist_head *head; - struct atm_vcc *vcc; - struct sock *s; - - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; - - sk_for_each(s, head) { - vcc = atm_sk(s); - if (vcc->dev == dev && - vcc->vci == vci && vcc->vpi == vpi && - vcc->qos.rxtp.traffic_class != ATM_NONE) { - return vcc; - } - } - return NULL; -} - -static int atmtcp_c_pre_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct atmtcp_hdr *hdr; - - if (skb->len < sizeof(struct atmtcp_hdr)) - return -EINVAL; - - hdr = (struct atmtcp_hdr *)skb->data; - if (hdr->length == ATMTCP_HDR_MAGIC) - return -EINVAL; - - return 0; -} - -static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) -{ - struct atm_dev *dev; - struct atmtcp_hdr *hdr; - struct atm_vcc *out_vcc; - struct sk_buff *new_skb; - int result = 0; - - dev = vcc->dev_data; - hdr = (struct atmtcp_hdr *) skb->data; - if (hdr->length == ATMTCP_HDR_MAGIC) { - result = atmtcp_recv_control( - (struct atmtcp_control *) skb->data); - goto done; - } - read_lock(&vcc_sklist_lock); - out_vcc = find_vcc(dev, ntohs(hdr->vpi), ntohs(hdr->vci)); - read_unlock(&vcc_sklist_lock); - if (!out_vcc) { - result = -EUNATCH; - atomic_inc(&vcc->stats->tx_err); - goto done; - } - skb_pull(skb,sizeof(struct atmtcp_hdr)); - new_skb = atm_alloc_charge(out_vcc,skb->len,GFP_KERNEL); - if (!new_skb) { - result = -ENOBUFS; - goto done; - } - __net_timestamp(new_skb); - skb_copy_from_linear_data(skb, skb_put(new_skb, skb->len), skb->len); - out_vcc->push(out_vcc,new_skb); - atomic_inc(&vcc->stats->tx); - atomic_inc(&out_vcc->stats->rx); -done: - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return result; -} - - -/* - * Device operations for the virtual ATM devices created by ATMTCP. - */ - - -static const struct atmdev_ops atmtcp_v_dev_ops = { - .dev_close = atmtcp_v_dev_close, - .open = atmtcp_v_open, - .close = atmtcp_v_close, - .ioctl = atmtcp_v_ioctl, - .send = atmtcp_v_send, - .proc_read = atmtcp_v_proc, - .owner = THIS_MODULE -}; - - -/* - * Device operations for the ATMTCP control device. - */ - - -static const struct atmdev_ops atmtcp_c_dev_ops = { - .close = atmtcp_c_close, - .pre_send = atmtcp_c_pre_send, - .send = atmtcp_c_send -}; - - -static struct atm_dev atmtcp_control_dev = { - .ops = &atmtcp_c_dev_ops, - .type = "atmtcp", - .number = 999, - .lock = __SPIN_LOCK_UNLOCKED(atmtcp_control_dev.lock) -}; - - -static int atmtcp_create(int itf,int persist,struct atm_dev **result) -{ - struct atmtcp_dev_data *dev_data; - struct atm_dev *dev; - - dev_data = kmalloc_obj(*dev_data); - if (!dev_data) - return -ENOMEM; - - dev = atm_dev_register(DEV_LABEL,NULL,&atmtcp_v_dev_ops,itf,NULL); - if (!dev) { - kfree(dev_data); - return itf == -1 ? -ENOMEM : -EBUSY; - } - dev->ci_range.vpi_bits = MAX_VPI_BITS; - dev->ci_range.vci_bits = MAX_VCI_BITS; - dev->dev_data = dev_data; - PRIV(dev)->vcc = NULL; - PRIV(dev)->persist = persist; - if (result) *result = dev; - return 0; -} - - -static int atmtcp_attach(struct atm_vcc *vcc,int itf) -{ - struct atm_dev *dev; - - dev = NULL; - if (itf != -1) dev = atm_dev_lookup(itf); - if (dev) { - if (dev->ops != &atmtcp_v_dev_ops) { - atm_dev_put(dev); - return -EMEDIUMTYPE; - } - if (PRIV(dev)->vcc) { - atm_dev_put(dev); - return -EBUSY; - } - } - else { - int error; - - error = atmtcp_create(itf,0,&dev); - if (error) return error; - } - PRIV(dev)->vcc = vcc; - vcc->dev = &atmtcp_control_dev; - vcc_insert_socket(sk_atm(vcc)); - set_bit(ATM_VF_META,&vcc->flags); - set_bit(ATM_VF_READY,&vcc->flags); - vcc->dev_data = dev; - (void) atm_init_aal5(vcc); /* @@@ losing AAL in transit ... */ - vcc->stats = &atmtcp_control_dev.stats.aal5; - return dev->number; -} - - -static int atmtcp_create_persistent(int itf) -{ - return atmtcp_create(itf,1,NULL); -} - - -static int atmtcp_remove_persistent(int itf) -{ - struct atm_dev *dev; - struct atmtcp_dev_data *dev_data; - - dev = atm_dev_lookup(itf); - if (!dev) return -ENODEV; - if (dev->ops != &atmtcp_v_dev_ops) { - atm_dev_put(dev); - return -EMEDIUMTYPE; - } - dev_data = PRIV(dev); - if (!dev_data->persist) { - atm_dev_put(dev); - return 0; - } - dev_data->persist = 0; - if (PRIV(dev)->vcc) { - atm_dev_put(dev); - return 0; - } - kfree(dev_data); - atm_dev_put(dev); - atm_dev_deregister(dev); - return 0; -} - -static int atmtcp_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - int err = 0; - struct atm_vcc *vcc = ATM_SD(sock); - - if (cmd != SIOCSIFATMTCP && cmd != ATMTCP_CREATE && cmd != ATMTCP_REMOVE) - return -ENOIOCTLCMD; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch (cmd) { - case SIOCSIFATMTCP: - err = atmtcp_attach(vcc, (int) arg); - if (err >= 0) { - sock->state = SS_CONNECTED; - __module_get(THIS_MODULE); - } - break; - case ATMTCP_CREATE: - err = atmtcp_create_persistent((int) arg); - break; - case ATMTCP_REMOVE: - err = atmtcp_remove_persistent((int) arg); - break; - } - return err; -} - -static struct atm_ioctl atmtcp_ioctl_ops = { - .owner = THIS_MODULE, - .ioctl = atmtcp_ioctl, -}; - -static __init int atmtcp_init(void) -{ - register_atm_ioctl(&atmtcp_ioctl_ops); - return 0; -} - - -static void __exit atmtcp_exit(void) -{ - deregister_atm_ioctl(&atmtcp_ioctl_ops); -} - -MODULE_DESCRIPTION("ATM over TCP"); -MODULE_LICENSE("GPL"); -module_init(atmtcp_init); -module_exit(atmtcp_exit); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c deleted file mode 100644 index 12cb3aa588bc..000000000000 --- a/drivers/atm/eni.c +++ /dev/null @@ -1,2321 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tonga.h" -#include "midway.h" -#include "suni.h" -#include "eni.h" - -/* - * TODO: - * - * Show stoppers - * none - * - * Minor - * - OAM support - * - fix bugs listed below - */ - -/* - * KNOWN BUGS: - * - * - may run into JK-JK bug and deadlock - * - should allocate UBR channel first - * - buffer space allocation algorithm is stupid - * (RX: should be maxSDU+maxdelay*rate - * TX: should be maxSDU+min(maxSDU,maxdelay*rate) ) - * - doesn't support OAM cells - * - eni_put_free may hang if not putting memory fragments that _complete_ - * 2^n block (never happens in real life, though) - */ - - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - -#ifndef CONFIG_ATM_ENI_TUNE_BURST -#define CONFIG_ATM_ENI_BURST_TX_8W -#define CONFIG_ATM_ENI_BURST_RX_4W -#endif - - -#ifndef CONFIG_ATM_ENI_DEBUG - - -#define NULLCHECK(x) - -#define EVENT(s,a,b) - - -static void event_dump(void) -{ -} - - -#else - - -/* - * NULL pointer checking - */ - -#define NULLCHECK(x) \ - if ((unsigned long) (x) < 0x30) \ - printk(KERN_CRIT #x "==0x%lx\n",(unsigned long) (x)) - -/* - * Very extensive activity logging. Greatly improves bug detection speed but - * costs a few Mbps if enabled. - */ - -#define EV 64 - -static const char *ev[EV]; -static unsigned long ev_a[EV],ev_b[EV]; -static int ec = 0; - - -static void EVENT(const char *s,unsigned long a,unsigned long b) -{ - ev[ec] = s; - ev_a[ec] = a; - ev_b[ec] = b; - ec = (ec+1) % EV; -} - - -static void event_dump(void) -{ - int n,i; - - for (n = 0; n < EV; n++) { - i = (ec+n) % EV; - printk(KERN_NOTICE); - printk(ev[i] ? ev[i] : "(null)",ev_a[i],ev_b[i]); - } -} - - -#endif /* CONFIG_ATM_ENI_DEBUG */ - - -/* - * NExx must not be equal at end - * EExx may be equal at end - * xxPJOK verify validity of pointer jumps - * xxPMOK operating on a circular buffer of "c" words - */ - -#define NEPJOK(a0,a1,b) \ - ((a0) < (a1) ? (b) <= (a0) || (b) > (a1) : (b) <= (a0) && (b) > (a1)) -#define EEPJOK(a0,a1,b) \ - ((a0) < (a1) ? (b) < (a0) || (b) >= (a1) : (b) < (a0) && (b) >= (a1)) -#define NEPMOK(a0,d,b,c) NEPJOK(a0,(a0+d) & (c-1),b) -#define EEPMOK(a0,d,b,c) EEPJOK(a0,(a0+d) & (c-1),b) - - -static int tx_complete = 0,dma_complete = 0,queued = 0,requeued = 0, - backlogged = 0,rx_enqueued = 0,rx_dequeued = 0,pushed = 0,submitted = 0, - putting = 0; - -static struct atm_dev *eni_boards = NULL; - -/* Read/write registers on card */ -#define eni_in(r) readl(eni_dev->reg+(r)*4) -#define eni_out(v,r) writel((v),eni_dev->reg+(r)*4) - - -/*-------------------------------- utilities --------------------------------*/ - - -static void dump_mem(struct eni_dev *eni_dev) -{ - int i; - - for (i = 0; i < eni_dev->free_len; i++) - printk(KERN_DEBUG " %d: %p %d\n",i, - eni_dev->free_list[i].start, - 1 << eni_dev->free_list[i].order); -} - - -static void dump(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - - int i; - - eni_dev = ENI_DEV(dev); - printk(KERN_NOTICE "Free memory\n"); - dump_mem(eni_dev); - printk(KERN_NOTICE "TX buffers\n"); - for (i = 0; i < NR_CHAN; i++) - if (eni_dev->tx[i].send) - printk(KERN_NOTICE " TX %d @ %p: %ld\n",i, - eni_dev->tx[i].send,eni_dev->tx[i].words*4); - printk(KERN_NOTICE "RX buffers\n"); - for (i = 0; i < 1024; i++) - if (eni_dev->rx_map[i] && ENI_VCC(eni_dev->rx_map[i])->rx) - printk(KERN_NOTICE " RX %d @ %p: %ld\n",i, - ENI_VCC(eni_dev->rx_map[i])->recv, - ENI_VCC(eni_dev->rx_map[i])->words*4); - printk(KERN_NOTICE "----\n"); -} - - -static void eni_put_free(struct eni_dev *eni_dev, void __iomem *start, - unsigned long size) -{ - struct eni_free *list; - int len,order; - - DPRINTK("init 0x%lx+%ld(0x%lx)\n",start,size,size); - start += eni_dev->base_diff; - list = eni_dev->free_list; - len = eni_dev->free_len; - while (size) { - if (len >= eni_dev->free_list_size) { - printk(KERN_CRIT "eni_put_free overflow (%p,%ld)\n", - start,size); - break; - } - for (order = 0; !(((unsigned long)start | size) & (1 << order)); order++); - if (MID_MIN_BUF_SIZE > (1 << order)) { - printk(KERN_CRIT "eni_put_free: order %d too small\n", - order); - break; - } - list[len].start = (void __iomem *) start; - list[len].order = order; - len++; - start += 1 << order; - size -= 1 << order; - } - eni_dev->free_len = len; - /*dump_mem(eni_dev);*/ -} - - -static void __iomem *eni_alloc_mem(struct eni_dev *eni_dev, unsigned long *size) -{ - struct eni_free *list; - void __iomem *start; - int len,i,order,best_order,index; - - list = eni_dev->free_list; - len = eni_dev->free_len; - if (*size < MID_MIN_BUF_SIZE) *size = MID_MIN_BUF_SIZE; - if (*size > MID_MAX_BUF_SIZE) return NULL; - for (order = 0; (1 << order) < *size; order++) - ; - DPRINTK("trying: %ld->%d\n",*size,order); - best_order = 65; /* we don't have more than 2^64 of anything ... */ - index = 0; /* silence GCC */ - for (i = 0; i < len; i++) - if (list[i].order == order) { - best_order = order; - index = i; - break; - } - else if (best_order > list[i].order && list[i].order > order) { - best_order = list[i].order; - index = i; - } - if (best_order == 65) return NULL; - start = list[index].start-eni_dev->base_diff; - list[index] = list[--len]; - eni_dev->free_len = len; - *size = 1 << order; - eni_put_free(eni_dev,start+*size,(1 << best_order)-*size); - DPRINTK("%ld bytes (order %d) at 0x%lx\n",*size,order,start); - memset_io(start,0,*size); /* never leak data */ - /*dump_mem(eni_dev);*/ - return start; -} - - -static void eni_free_mem(struct eni_dev *eni_dev, void __iomem *start, - unsigned long size) -{ - struct eni_free *list; - int len,i,order; - - start += eni_dev->base_diff; - list = eni_dev->free_list; - len = eni_dev->free_len; - for (order = -1; size; order++) size >>= 1; - DPRINTK("eni_free_mem: %p+0x%lx (order %d)\n",start,size,order); - for (i = 0; i < len; i++) - if (((unsigned long) list[i].start) == ((unsigned long)start^(1 << order)) && - list[i].order == order) { - DPRINTK("match[%d]: 0x%lx/0x%lx(0x%x), %d/%d\n",i, - list[i].start,start,1 << order,list[i].order,order); - list[i] = list[--len]; - start = (void __iomem *) ((unsigned long) start & ~(unsigned long) (1 << order)); - order++; - i = -1; - continue; - } - if (len >= eni_dev->free_list_size) { - printk(KERN_ALERT "eni_free_mem overflow (%p,%d)\n",start, - order); - return; - } - list[len].start = start; - list[len].order = order; - eni_dev->free_len = len+1; - /*dump_mem(eni_dev);*/ -} - - -/*----------------------------------- RX ------------------------------------*/ - - -#define ENI_VCC_NOS ((struct atm_vcc *) 1) - - -static void rx_ident_err(struct atm_vcc *vcc) -{ - struct atm_dev *dev; - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - - dev = vcc->dev; - eni_dev = ENI_DEV(dev); - /* immediately halt adapter */ - eni_out(eni_in(MID_MC_S) & - ~(MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE),MID_MC_S); - /* dump useful information */ - eni_vcc = ENI_VCC(vcc); - printk(KERN_ALERT DEV_LABEL "(itf %d): driver error - RX ident " - "mismatch\n",dev->number); - printk(KERN_ALERT " VCI %d, rxing %d, words %ld\n",vcc->vci, - eni_vcc->rxing,eni_vcc->words); - printk(KERN_ALERT " host descr 0x%lx, rx pos 0x%lx, descr value " - "0x%x\n",eni_vcc->descr,eni_vcc->rx_pos, - (unsigned) readl(eni_vcc->recv+eni_vcc->descr*4)); - printk(KERN_ALERT " last %p, servicing %d\n",eni_vcc->last, - eni_vcc->servicing); - EVENT("---dump ends here---\n",0,0); - printk(KERN_NOTICE "---recent events---\n"); - event_dump(); - ENI_DEV(dev)->fast = NULL; /* really stop it */ - ENI_DEV(dev)->slow = NULL; - skb_queue_head_init(&ENI_DEV(dev)->rx_queue); -} - - -static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, - unsigned long skip,unsigned long size,unsigned long eff) -{ - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - u32 dma_rd,dma_wr; - u32 dma[RX_DMA_BUF*2]; - dma_addr_t paddr; - unsigned long here; - int i,j; - - eni_dev = ENI_DEV(vcc->dev); - eni_vcc = ENI_VCC(vcc); - paddr = 0; /* GCC, shut up */ - if (skb) { - paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, - DMA_FROM_DEVICE); - if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) - goto dma_map_error; - ENI_PRV_PADDR(skb) = paddr; - if (paddr & 3) - printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d has " - "mis-aligned RX data (0x%lx)\n",vcc->dev->number, - vcc->vci,(unsigned long) paddr); - ENI_PRV_SIZE(skb) = size+skip; - /* PDU plus descriptor */ - ATM_SKB(skb)->vcc = vcc; - } - j = 0; - if ((eff && skip) || 1) { /* @@@ actually, skip is always == 1 ... */ - here = (eni_vcc->descr+skip) & (eni_vcc->words-1); - dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci - << MID_DMA_VCI_SHIFT) | MID_DT_JK; - dma[j++] = 0; - } - here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1); - if (!eff) size += skip; - else { - unsigned long words; - - if (!size) { - DPRINTK("strange things happen ...\n"); - EVENT("strange things happen ... (skip=%ld,eff=%ld)\n", - size,eff); - } - words = eff; - if (paddr & 15) { - unsigned long init; - - init = 4-((paddr & 15) >> 2); - if (init > words) init = words; - dma[j++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | - (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - paddr += init << 2; - words -= init; - } -#ifdef CONFIG_ATM_ENI_BURST_RX_16W /* may work with some PCI chipsets ... */ - if (words & ~15) { - dma[j++] = MID_DT_16W | ((words >> 4) << - MID_DMA_COUNT_SHIFT) | (vcc->vci << - MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - paddr += (words & ~15) << 2; - words &= 15; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_8W /* works only with *some* PCI chipsets ... */ - if (words & ~7) { - dma[j++] = MID_DT_8W | ((words >> 3) << - MID_DMA_COUNT_SHIFT) | (vcc->vci << - MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - paddr += (words & ~7) << 2; - words &= 7; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_4W /* recommended */ - if (words & ~3) { - dma[j++] = MID_DT_4W | ((words >> 2) << - MID_DMA_COUNT_SHIFT) | (vcc->vci << - MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - paddr += (words & ~3) << 2; - words &= 3; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_2W /* probably useless if RX_4W, RX_8W, ... */ - if (words & ~1) { - dma[j++] = MID_DT_2W | ((words >> 1) << - MID_DMA_COUNT_SHIFT) | (vcc->vci << - MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - paddr += (words & ~1) << 2; - words &= 1; - } -#endif - if (words) { - dma[j++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) - | (vcc->vci << MID_DMA_VCI_SHIFT); - dma[j++] = paddr; - } - } - if (size != eff) { - dma[j++] = (here << MID_DMA_COUNT_SHIFT) | - (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; - dma[j++] = 0; - } - if (!j || j > 2*RX_DMA_BUF) { - printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); - goto trouble; - } - dma[j-2] |= MID_DMA_END; - j = j >> 1; - dma_wr = eni_in(MID_DMA_WR_RX); - dma_rd = eni_in(MID_DMA_RD_RX); - /* - * Can I move the dma_wr pointer by 2j+1 positions without overwriting - * data that hasn't been read (position of dma_rd) yet ? - */ - if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ - printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", - vcc->dev->number); - goto trouble; - } - for (i = 0; i < j; i++) { - writel(dma[i*2],eni_dev->rx_dma+dma_wr*8); - writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*8+4); - dma_wr = (dma_wr+1) & (NR_DMA_RX-1); - } - if (skb) { - ENI_PRV_POS(skb) = eni_vcc->descr+size+1; - skb_queue_tail(&eni_dev->rx_queue,skb); - eni_vcc->last = skb; - rx_enqueued++; - } - eni_vcc->descr = here; - eni_out(dma_wr,MID_DMA_WR_RX); - return 0; - -trouble: - if (paddr) - dma_unmap_single(&eni_dev->pci_dev->dev,paddr,skb->len, - DMA_FROM_DEVICE); -dma_map_error: - if (skb) dev_kfree_skb_irq(skb); - return -1; -} - - -static void discard(struct atm_vcc *vcc,unsigned long size) -{ - struct eni_vcc *eni_vcc; - - eni_vcc = ENI_VCC(vcc); - EVENT("discard (size=%ld)\n",size,0); - while (do_rx_dma(vcc,NULL,1,size,0)) EVENT("BUSY LOOP",0,0); - /* could do a full fallback, but that might be more expensive */ - if (eni_vcc->rxing) ENI_PRV_POS(eni_vcc->last) += size+1; - else eni_vcc->rx_pos = (eni_vcc->rx_pos+size+1) & (eni_vcc->words-1); -} - - -/* - * TODO: should check whether direct copies (without DMA setup, dequeuing on - * interrupt, etc.) aren't much faster for AAL0 - */ - -static int rx_aal0(struct atm_vcc *vcc) -{ - struct eni_vcc *eni_vcc; - unsigned long descr; - unsigned long length; - struct sk_buff *skb; - - DPRINTK(">rx_aal0\n"); - eni_vcc = ENI_VCC(vcc); - descr = readl(eni_vcc->recv+eni_vcc->descr*4); - if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { - rx_ident_err(vcc); - return 1; - } - if (descr & MID_RED_T) { - DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", - vcc->dev->number); - length = 0; - atomic_inc(&vcc->stats->rx_err); - } - else { - length = ATM_CELL_SIZE-1; /* no HEC */ - } - skb = length ? atm_alloc_charge(vcc,length,GFP_ATOMIC) : NULL; - if (!skb) { - discard(vcc,length >> 2); - return 0; - } - skb_put(skb,length); - skb->tstamp = eni_vcc->timestamp; - DPRINTK("got len %ld\n",length); - if (do_rx_dma(vcc,skb,1,length >> 2,length >> 2)) return 1; - eni_vcc->rxing++; - return 0; -} - - -static int rx_aal5(struct atm_vcc *vcc) -{ - struct eni_vcc *eni_vcc; - unsigned long descr; - unsigned long size,eff,length; - struct sk_buff *skb; - - EVENT("rx_aal5\n",0,0); - DPRINTK(">rx_aal5\n"); - eni_vcc = ENI_VCC(vcc); - descr = readl(eni_vcc->recv+eni_vcc->descr*4); - if ((descr & MID_RED_IDEN) != (MID_RED_RX_ID << MID_RED_SHIFT)) { - rx_ident_err(vcc); - return 1; - } - if (descr & (MID_RED_T | MID_RED_CRC_ERR)) { - if (descr & MID_RED_T) { - EVENT("empty cell (descr=0x%lx)\n",descr,0); - DPRINTK(DEV_LABEL "(itf %d): trashing empty cell\n", - vcc->dev->number); - size = 0; - } - else { - static unsigned long silence = 0; - - if (time_after(jiffies, silence) || silence == 0) { - printk(KERN_WARNING DEV_LABEL "(itf %d): " - "discarding PDU(s) with CRC error\n", - vcc->dev->number); - silence = (jiffies+2*HZ)|1; - } - size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); - EVENT("CRC error (descr=0x%lx,size=%ld)\n",descr, - size); - } - eff = length = 0; - atomic_inc(&vcc->stats->rx_err); - } - else { - size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2); - DPRINTK("size=%ld\n",size); - length = readl(eni_vcc->recv+(((eni_vcc->descr+size-1) & - (eni_vcc->words-1)))*4) & 0xffff; - /* -trailer(2)+header(1) */ - if (length && length <= (size << 2)-8 && length <= - ATM_MAX_AAL5_PDU) eff = (length+3) >> 2; - else { /* ^ trailer length (8) */ - EVENT("bad PDU (descr=0x08%lx,length=%ld)\n",descr, - length); - printk(KERN_ERR DEV_LABEL "(itf %d): bad AAL5 PDU " - "(VCI=%d,length=%ld,size=%ld (descr 0x%lx))\n", - vcc->dev->number,vcc->vci,length,size << 2,descr); - length = eff = 0; - atomic_inc(&vcc->stats->rx_err); - } - } - skb = eff ? atm_alloc_charge(vcc,eff << 2,GFP_ATOMIC) : NULL; - if (!skb) { - discard(vcc,size); - return 0; - } - skb_put(skb,length); - DPRINTK("got len %ld\n",length); - if (do_rx_dma(vcc,skb,1,size,eff)) return 1; - eni_vcc->rxing++; - return 0; -} - - -static inline int rx_vcc(struct atm_vcc *vcc) -{ - void __iomem *vci_dsc; - unsigned long tmp; - struct eni_vcc *eni_vcc; - - eni_vcc = ENI_VCC(vcc); - vci_dsc = ENI_DEV(vcc->dev)->vci+vcc->vci*16; - EVENT("rx_vcc(1)\n",0,0); - while (eni_vcc->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) >> - MID_VCI_DESCR_SHIFT)) { - EVENT("rx_vcc(2: host dsc=0x%lx, nic dsc=0x%lx)\n", - eni_vcc->descr,tmp); - DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, - (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >> - MID_VCI_DESCR_SHIFT)); - if (ENI_VCC(vcc)->rx(vcc)) return 1; - } - /* clear IN_SERVICE flag */ - writel(readl(vci_dsc) & ~MID_VCI_IN_SERVICE,vci_dsc); - /* - * If new data has arrived between evaluating the while condition and - * clearing IN_SERVICE, we wouldn't be notified until additional data - * follows. So we have to loop again to be sure. - */ - EVENT("rx_vcc(3)\n",0,0); - while (ENI_VCC(vcc)->descr != (tmp = (readl(vci_dsc+4) & MID_VCI_DESCR) - >> MID_VCI_DESCR_SHIFT)) { - EVENT("rx_vcc(4: host dsc=0x%lx, nic dsc=0x%lx)\n", - eni_vcc->descr,tmp); - DPRINTK("CB_DESCR %ld REG_DESCR %d\n",ENI_VCC(vcc)->descr, - (((unsigned) readl(vci_dsc+4) & MID_VCI_DESCR) >> - MID_VCI_DESCR_SHIFT)); - if (ENI_VCC(vcc)->rx(vcc)) return 1; - } - return 0; -} - - -static void poll_rx(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - struct atm_vcc *curr; - - eni_dev = ENI_DEV(dev); - while ((curr = eni_dev->fast)) { - EVENT("poll_rx.fast\n",0,0); - if (rx_vcc(curr)) return; - eni_dev->fast = ENI_VCC(curr)->next; - ENI_VCC(curr)->next = ENI_VCC_NOS; - barrier(); - ENI_VCC(curr)->servicing--; - } - while ((curr = eni_dev->slow)) { - EVENT("poll_rx.slow\n",0,0); - if (rx_vcc(curr)) return; - eni_dev->slow = ENI_VCC(curr)->next; - ENI_VCC(curr)->next = ENI_VCC_NOS; - barrier(); - ENI_VCC(curr)->servicing--; - } -} - - -static void get_service(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - struct atm_vcc *vcc; - unsigned long vci; - - DPRINTK(">get_service\n"); - eni_dev = ENI_DEV(dev); - while (eni_in(MID_SERV_WRITE) != eni_dev->serv_read) { - vci = readl(eni_dev->service+eni_dev->serv_read*4); - eni_dev->serv_read = (eni_dev->serv_read+1) & (NR_SERVICE-1); - vcc = eni_dev->rx_map[vci & 1023]; - if (!vcc) { - printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %ld not " - "found\n",dev->number,vci); - continue; /* nasty but we try to go on anyway */ - /* @@@ nope, doesn't work */ - } - EVENT("getting from service\n",0,0); - if (ENI_VCC(vcc)->next != ENI_VCC_NOS) { - EVENT("double service\n",0,0); - DPRINTK("Grr, servicing VCC %ld twice\n",vci); - continue; - } - ENI_VCC(vcc)->timestamp = ktime_get_real(); - ENI_VCC(vcc)->next = NULL; - if (vcc->qos.rxtp.traffic_class == ATM_CBR) { - if (eni_dev->fast) - ENI_VCC(eni_dev->last_fast)->next = vcc; - else eni_dev->fast = vcc; - eni_dev->last_fast = vcc; - } - else { - if (eni_dev->slow) - ENI_VCC(eni_dev->last_slow)->next = vcc; - else eni_dev->slow = vcc; - eni_dev->last_slow = vcc; - } - putting++; - ENI_VCC(vcc)->servicing++; - } -} - - -static void dequeue_rx(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - struct atm_vcc *vcc; - struct sk_buff *skb; - void __iomem *vci_dsc; - int first; - - eni_dev = ENI_DEV(dev); - first = 1; - while (1) { - skb = skb_dequeue(&eni_dev->rx_queue); - if (!skb) { - if (first) { - DPRINTK(DEV_LABEL "(itf %d): RX but not " - "rxing\n",dev->number); - EVENT("nothing to dequeue\n",0,0); - } - break; - } - EVENT("dequeued (size=%ld,pos=0x%lx)\n",ENI_PRV_SIZE(skb), - ENI_PRV_POS(skb)); - rx_dequeued++; - vcc = ATM_SKB(skb)->vcc; - eni_vcc = ENI_VCC(vcc); - first = 0; - vci_dsc = eni_dev->vci+vcc->vci*16; - if (!EEPMOK(eni_vcc->rx_pos,ENI_PRV_SIZE(skb), - (readl(vci_dsc+4) & MID_VCI_READ) >> MID_VCI_READ_SHIFT, - eni_vcc->words)) { - EVENT("requeuing\n",0,0); - skb_queue_head(&eni_dev->rx_queue,skb); - break; - } - eni_vcc->rxing--; - eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1); - dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len, - DMA_TO_DEVICE); - if (!skb->len) dev_kfree_skb_irq(skb); - else { - EVENT("pushing (len=%ld)\n",skb->len,0); - if (vcc->qos.aal == ATM_AAL0) - *(unsigned long *) skb->data = - ntohl(*(unsigned long *) skb->data); - memset(skb->cb,0,sizeof(struct eni_skb_prv)); - vcc->push(vcc,skb); - pushed++; - } - atomic_inc(&vcc->stats->rx); - } - wake_up(&eni_dev->rx_wait); -} - - -static int open_rx_first(struct atm_vcc *vcc) -{ - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - unsigned long size; - - DPRINTK("open_rx_first\n"); - eni_dev = ENI_DEV(vcc->dev); - eni_vcc = ENI_VCC(vcc); - eni_vcc->rx = NULL; - if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; - size = vcc->qos.rxtp.max_sdu*eni_dev->rx_mult/100; - if (size > MID_MAX_BUF_SIZE && vcc->qos.rxtp.max_sdu <= - MID_MAX_BUF_SIZE) - size = MID_MAX_BUF_SIZE; - eni_vcc->recv = eni_alloc_mem(eni_dev,&size); - DPRINTK("rx at 0x%lx\n",eni_vcc->recv); - eni_vcc->words = size >> 2; - if (!eni_vcc->recv) return -ENOBUFS; - eni_vcc->rx = vcc->qos.aal == ATM_AAL5 ? rx_aal5 : rx_aal0; - eni_vcc->descr = 0; - eni_vcc->rx_pos = 0; - eni_vcc->rxing = 0; - eni_vcc->servicing = 0; - eni_vcc->next = ENI_VCC_NOS; - return 0; -} - - -static int open_rx_second(struct atm_vcc *vcc) -{ - void __iomem *here; - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - unsigned long size; - int order; - - DPRINTK("open_rx_second\n"); - eni_dev = ENI_DEV(vcc->dev); - eni_vcc = ENI_VCC(vcc); - if (!eni_vcc->rx) return 0; - /* set up VCI descriptor */ - here = eni_dev->vci+vcc->vci*16; - DPRINTK("loc 0x%x\n",(unsigned) (eni_vcc->recv-eni_dev->ram)/4); - size = eni_vcc->words >> 8; - for (order = -1; size; order++) size >>= 1; - writel(0,here+4); /* descr, read = 0 */ - writel(0,here+8); /* write, state, count = 0 */ - if (eni_dev->rx_map[vcc->vci]) - printk(KERN_CRIT DEV_LABEL "(itf %d): BUG - VCI %d already " - "in use\n",vcc->dev->number,vcc->vci); - eni_dev->rx_map[vcc->vci] = vcc; /* now it counts */ - writel(((vcc->qos.aal != ATM_AAL5 ? MID_MODE_RAW : MID_MODE_AAL5) << - MID_VCI_MODE_SHIFT) | MID_VCI_PTI_MODE | - (((eni_vcc->recv-eni_dev->ram) >> (MID_LOC_SKIP+2)) << - MID_VCI_LOCATION_SHIFT) | (order << MID_VCI_SIZE_SHIFT),here); - return 0; -} - - -static void close_rx(struct atm_vcc *vcc) -{ - DECLARE_WAITQUEUE(wait,current); - void __iomem *here; - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - - eni_vcc = ENI_VCC(vcc); - if (!eni_vcc->rx) return; - eni_dev = ENI_DEV(vcc->dev); - if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { - here = eni_dev->vci+vcc->vci*16; - /* block receiver */ - writel((readl(here) & ~MID_VCI_MODE) | (MID_MODE_TRASH << - MID_VCI_MODE_SHIFT),here); - /* wait for receiver to become idle */ - udelay(27); - /* discard pending cell */ - writel(readl(here) & ~MID_VCI_IN_SERVICE,here); - /* don't accept any new ones */ - eni_dev->rx_map[vcc->vci] = NULL; - /* wait for RX queue to drain */ - DPRINTK("eni_close: waiting for RX ...\n"); - EVENT("RX closing\n",0,0); - add_wait_queue(&eni_dev->rx_wait,&wait); - set_current_state(TASK_UNINTERRUPTIBLE); - barrier(); - for (;;) { - /* transition service->rx: rxing++, servicing-- */ - if (!eni_vcc->servicing) { - barrier(); - if (!eni_vcc->rxing) break; - } - EVENT("drain PDUs (rx %ld, serv %ld)\n",eni_vcc->rxing, - eni_vcc->servicing); - printk(KERN_INFO "%d+%d RX left\n",eni_vcc->servicing, - eni_vcc->rxing); - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - for (;;) { - int at_end; - u32 tmp; - - tasklet_disable(&eni_dev->task); - tmp = readl(eni_dev->vci+vcc->vci*16+4) & MID_VCI_READ; - at_end = eni_vcc->rx_pos == tmp >> MID_VCI_READ_SHIFT; - tasklet_enable(&eni_dev->task); - if (at_end) break; - EVENT("drain discard (host 0x%lx, nic 0x%lx)\n", - eni_vcc->rx_pos,tmp); - printk(KERN_INFO "draining RX: host 0x%lx, nic 0x%x\n", - eni_vcc->rx_pos,tmp); - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&eni_dev->rx_wait,&wait); - } - eni_free_mem(eni_dev,eni_vcc->recv,eni_vcc->words << 2); - eni_vcc->rx = NULL; -} - - -static int start_rx(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - - eni_dev = ENI_DEV(dev); - eni_dev->rx_map = (struct atm_vcc **) get_zeroed_page(GFP_KERNEL); - if (!eni_dev->rx_map) { - printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", - dev->number); - free_page((unsigned long) eni_dev->free_list); - return -ENOMEM; - } - eni_dev->rx_mult = DEFAULT_RX_MULT; - eni_dev->fast = eni_dev->last_fast = NULL; - eni_dev->slow = eni_dev->last_slow = NULL; - init_waitqueue_head(&eni_dev->rx_wait); - skb_queue_head_init(&eni_dev->rx_queue); - eni_dev->serv_read = eni_in(MID_SERV_WRITE); - eni_out(0,MID_DMA_WR_RX); - return 0; -} - - -/*----------------------------------- TX ------------------------------------*/ - - -enum enq_res { enq_ok,enq_next,enq_jam }; - - -static inline void put_dma(int chan,u32 *dma,int *j,dma_addr_t paddr, - u32 size) -{ - u32 init,words; - - DPRINTK("put_dma: 0x%lx+0x%x\n",(unsigned long) paddr,size); - EVENT("put_dma: 0x%lx+0x%lx\n",(unsigned long) paddr,size); -#if 0 /* don't complain anymore */ - if (paddr & 3) - printk(KERN_ERR "put_dma: unaligned addr (0x%lx)\n",paddr); - if (size & 3) - printk(KERN_ERR "put_dma: unaligned size (0x%lx)\n",size); -#endif - if (paddr & 3) { - init = 4-(paddr & 3); - if (init > size || size < 7) init = size; - DPRINTK("put_dma: %lx DMA: %d/%d bytes\n", - (unsigned long) paddr,init,size); - dma[(*j)++] = MID_DT_BYTE | (init << MID_DMA_COUNT_SHIFT) | - (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += init; - size -= init; - } - words = size >> 2; - size &= 3; - if (words && (paddr & 31)) { - init = 8-((paddr & 31) >> 2); - if (init > words) init = words; - DPRINTK("put_dma: %lx DMA: %d/%d words\n", - (unsigned long) paddr,init,words); - dma[(*j)++] = MID_DT_WORD | (init << MID_DMA_COUNT_SHIFT) | - (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += init << 2; - words -= init; - } -#ifdef CONFIG_ATM_ENI_BURST_TX_16W /* may work with some PCI chipsets ... */ - if (words & ~15) { - DPRINTK("put_dma: %lx DMA: %d*16/%d words\n", - (unsigned long) paddr,words >> 4,words); - dma[(*j)++] = MID_DT_16W | ((words >> 4) << MID_DMA_COUNT_SHIFT) - | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += (words & ~15) << 2; - words &= 15; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_8W /* recommended */ - if (words & ~7) { - DPRINTK("put_dma: %lx DMA: %d*8/%d words\n", - (unsigned long) paddr,words >> 3,words); - dma[(*j)++] = MID_DT_8W | ((words >> 3) << MID_DMA_COUNT_SHIFT) - | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += (words & ~7) << 2; - words &= 7; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_4W /* probably useless if TX_8W or TX_16W */ - if (words & ~3) { - DPRINTK("put_dma: %lx DMA: %d*4/%d words\n", - (unsigned long) paddr,words >> 2,words); - dma[(*j)++] = MID_DT_4W | ((words >> 2) << MID_DMA_COUNT_SHIFT) - | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += (words & ~3) << 2; - words &= 3; - } -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_2W /* probably useless if TX_4W, TX_8W, ... */ - if (words & ~1) { - DPRINTK("put_dma: %lx DMA: %d*2/%d words\n", - (unsigned long) paddr,words >> 1,words); - dma[(*j)++] = MID_DT_2W | ((words >> 1) << MID_DMA_COUNT_SHIFT) - | (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += (words & ~1) << 2; - words &= 1; - } -#endif - if (words) { - DPRINTK("put_dma: %lx DMA: %d words\n",(unsigned long) paddr, - words); - dma[(*j)++] = MID_DT_WORD | (words << MID_DMA_COUNT_SHIFT) | - (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - paddr += words << 2; - } - if (size) { - DPRINTK("put_dma: %lx DMA: %d bytes\n",(unsigned long) paddr, - size); - dma[(*j)++] = MID_DT_BYTE | (size << MID_DMA_COUNT_SHIFT) | - (chan << MID_DMA_CHAN_SHIFT); - dma[(*j)++] = paddr; - } -} - - -static enum enq_res do_tx(struct sk_buff *skb) -{ - struct atm_vcc *vcc; - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - struct eni_tx *tx; - dma_addr_t paddr; - u32 dma_rd,dma_wr; - u32 size; /* in words */ - int aal5,dma_size,i,j; - unsigned char skb_data3; - - DPRINTK(">do_tx\n"); - NULLCHECK(skb); - EVENT("do_tx: skb=0x%lx, %ld bytes\n",(unsigned long) skb,skb->len); - vcc = ATM_SKB(skb)->vcc; - NULLCHECK(vcc); - eni_dev = ENI_DEV(vcc->dev); - NULLCHECK(eni_dev); - eni_vcc = ENI_VCC(vcc); - tx = eni_vcc->tx; - NULLCHECK(tx); -#if 0 /* Enable this for testing with the "align" program */ - { - unsigned int hack = *((char *) skb->data)-'0'; - - if (hack < 8) { - skb->data += hack; - skb->len -= hack; - } - } -#endif -#if 0 /* should work now */ - if ((unsigned long) skb->data & 3) - printk(KERN_ERR DEV_LABEL "(itf %d): VCI %d has mis-aligned " - "TX data\n",vcc->dev->number,vcc->vci); -#endif - /* - * Potential future IP speedup: make hard_header big enough to put - * segmentation descriptor directly into PDU. Saves: 4 slave writes, - * 1 DMA xfer & 2 DMA'ed bytes (protocol layering is for wimps :-) - */ - - aal5 = vcc->qos.aal == ATM_AAL5; - /* check space in buffer */ - if (!aal5) - size = (ATM_CELL_PAYLOAD >> 2)+TX_DESCR_SIZE; - /* cell without HEC plus segmentation header (includes - four-byte cell header) */ - else { - size = skb->len+4*AAL5_TRAILER+ATM_CELL_PAYLOAD-1; - /* add AAL5 trailer */ - size = ((size-(size % ATM_CELL_PAYLOAD)) >> 2)+TX_DESCR_SIZE; - /* add segmentation header */ - } - /* - * Can I move tx_pos by size bytes without getting closer than TX_GAP - * to the read pointer ? TX_GAP means to leave some space for what - * the manual calls "too close". - */ - if (!NEPMOK(tx->tx_pos,size+TX_GAP, - eni_in(MID_TX_RDPTR(tx->index)),tx->words)) { - DPRINTK(DEV_LABEL "(itf %d): TX full (size %d)\n", - vcc->dev->number,size); - return enq_next; - } - /* check DMA */ - dma_wr = eni_in(MID_DMA_WR_TX); - dma_rd = eni_in(MID_DMA_RD_TX); - dma_size = 3; /* JK for descriptor and final fill, plus final size - mis-alignment fix */ -DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags); - if (!skb_shinfo(skb)->nr_frags) dma_size += 5; - else dma_size += 5*(skb_shinfo(skb)->nr_frags+1); - if (dma_size > TX_DMA_BUF) { - printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries " - "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF); - } - DPRINTK("dma_wr is %d, tx_pos is %ld\n",dma_wr,tx->tx_pos); - if (dma_wr != dma_rd && ((dma_rd+NR_DMA_TX-dma_wr) & (NR_DMA_TX-1)) < - dma_size) { - printk(KERN_WARNING DEV_LABEL "(itf %d): TX DMA full\n", - vcc->dev->number); - return enq_jam; - } - skb_data3 = skb->data[3]; - paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len, - DMA_TO_DEVICE); - if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr)) - return enq_next; - ENI_PRV_PADDR(skb) = paddr; - /* prepare DMA queue entries */ - j = 0; - eni_dev->dma[j++] = (((tx->tx_pos+TX_DESCR_SIZE) & (tx->words-1)) << - MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | - MID_DT_JK; - j++; - if (!skb_shinfo(skb)->nr_frags) - if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len); - else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4); - else { -DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */ - for (i = -1; i < skb_shinfo(skb)->nr_frags; i++) - if (i == -1) - put_dma(tx->index,eni_dev->dma,&j,(unsigned long) - skb->data, - skb_headlen(skb)); - else - put_dma(tx->index,eni_dev->dma,&j,(unsigned long) - skb_frag_page(&skb_shinfo(skb)->frags[i]) + - skb_frag_off(&skb_shinfo(skb)->frags[i]), - skb_frag_size(&skb_shinfo(skb)->frags[i])); - } - if (skb->len & 3) { - put_dma(tx->index, eni_dev->dma, &j, eni_dev->zero.dma, - 4 - (skb->len & 3)); - } - /* JK for AAL5 trailer - AAL0 doesn't need it, but who cares ... */ - eni_dev->dma[j++] = (((tx->tx_pos+size) & (tx->words-1)) << - MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) | - MID_DMA_END | MID_DT_JK; - j++; - DPRINTK("DMA at end: %d\n",j); - /* store frame */ - writel((MID_SEG_TX_ID << MID_SEG_ID_SHIFT) | - (aal5 ? MID_SEG_AAL5 : 0) | (tx->prescaler << MID_SEG_PR_SHIFT) | - (tx->resolution << MID_SEG_RATE_SHIFT) | - (size/(ATM_CELL_PAYLOAD/4)),tx->send+tx->tx_pos*4); -/*printk("dsc = 0x%08lx\n",(unsigned long) readl(tx->send+tx->tx_pos*4));*/ - writel((vcc->vci << MID_SEG_VCI_SHIFT) | - (aal5 ? 0 : (skb_data3 & 0xf)) | - (ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? MID_SEG_CLP : 0), - tx->send+((tx->tx_pos+1) & (tx->words-1))*4); - DPRINTK("size: %d, len:%d\n",size,skb->len); - if (aal5) - writel(skb->len,tx->send+ - ((tx->tx_pos+size-AAL5_TRAILER) & (tx->words-1))*4); - j = j >> 1; - for (i = 0; i < j; i++) { - writel(eni_dev->dma[i*2],eni_dev->tx_dma+dma_wr*8); - writel(eni_dev->dma[i*2+1],eni_dev->tx_dma+dma_wr*8+4); - dma_wr = (dma_wr+1) & (NR_DMA_TX-1); - } - ENI_PRV_POS(skb) = tx->tx_pos; - ENI_PRV_SIZE(skb) = size; - ENI_VCC(vcc)->txing += size; - tx->tx_pos = (tx->tx_pos+size) & (tx->words-1); - DPRINTK("dma_wr set to %d, tx_pos is now %ld\n",dma_wr,tx->tx_pos); - eni_out(dma_wr,MID_DMA_WR_TX); - skb_queue_tail(&eni_dev->tx_queue,skb); - queued++; - return enq_ok; -} - - -static void poll_tx(struct atm_dev *dev) -{ - struct eni_tx *tx; - struct sk_buff *skb; - enum enq_res res; - int i; - - DPRINTK(">poll_tx\n"); - for (i = NR_CHAN-1; i >= 0; i--) { - tx = &ENI_DEV(dev)->tx[i]; - if (tx->send) - while ((skb = skb_dequeue(&tx->backlog))) { - res = do_tx(skb); - if (res == enq_ok) continue; - DPRINTK("re-queuing TX PDU\n"); - skb_queue_head(&tx->backlog,skb); - requeued++; - if (res == enq_jam) return; - break; - } - } -} - - -static void dequeue_tx(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - struct atm_vcc *vcc; - struct sk_buff *skb; - struct eni_tx *tx; - - NULLCHECK(dev); - eni_dev = ENI_DEV(dev); - NULLCHECK(eni_dev); - while ((skb = skb_dequeue(&eni_dev->tx_queue))) { - vcc = ATM_SKB(skb)->vcc; - NULLCHECK(vcc); - tx = ENI_VCC(vcc)->tx; - NULLCHECK(ENI_VCC(vcc)->tx); - DPRINTK("dequeue_tx: next 0x%lx curr 0x%x\n",ENI_PRV_POS(skb), - (unsigned) eni_in(MID_TX_DESCRSTART(tx->index))); - if (ENI_VCC(vcc)->txing < tx->words && ENI_PRV_POS(skb) == - eni_in(MID_TX_DESCRSTART(tx->index))) { - skb_queue_head(&eni_dev->tx_queue,skb); - break; - } - ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb); - dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len, - DMA_TO_DEVICE); - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb_irq(skb); - atomic_inc(&vcc->stats->tx); - wake_up(&eni_dev->tx_wait); - dma_complete++; - } -} - - -static struct eni_tx *alloc_tx(struct eni_dev *eni_dev,int ubr) -{ - int i; - - for (i = !ubr; i < NR_CHAN; i++) - if (!eni_dev->tx[i].send) return eni_dev->tx+i; - return NULL; -} - - -static int comp_tx(struct eni_dev *eni_dev,int *pcr,int reserved,int *pre, - int *res,int unlimited) -{ - static const int pre_div[] = { 4,16,128,2048 }; - /* 2^(((x+2)^2-(x+2))/2+1) */ - - if (unlimited) *pre = *res = 0; - else { - if (*pcr > 0) { - int div; - - for (*pre = 0; *pre < 3; (*pre)++) - if (TS_CLOCK/pre_div[*pre]/64 <= *pcr) break; - div = pre_div[*pre]**pcr; - DPRINTK("min div %d\n",div); - *res = TS_CLOCK/div-1; - } - else { - int div; - - if (!*pcr) *pcr = eni_dev->tx_bw+reserved; - for (*pre = 3; *pre >= 0; (*pre)--) - if (TS_CLOCK/pre_div[*pre]/64 > -*pcr) break; - if (*pre < 3) (*pre)++; /* else fail later */ - div = pre_div[*pre]*-*pcr; - DPRINTK("max div %d\n",div); - *res = DIV_ROUND_UP(TS_CLOCK, div)-1; - } - if (*res < 0) *res = 0; - if (*res > MID_SEG_MAX_RATE) *res = MID_SEG_MAX_RATE; - } - *pcr = TS_CLOCK/pre_div[*pre]/(*res+1); - DPRINTK("out pcr: %d (%d:%d)\n",*pcr,*pre,*res); - return 0; -} - - -static int reserve_or_set_tx(struct atm_vcc *vcc,struct atm_trafprm *txtp, - int set_rsv,int set_shp) -{ - struct eni_dev *eni_dev = ENI_DEV(vcc->dev); - struct eni_vcc *eni_vcc = ENI_VCC(vcc); - struct eni_tx *tx; - unsigned long size; - void __iomem *mem; - int rate,ubr,unlimited,new_tx; - int pre,res,order; - int error; - - rate = atm_pcr_goal(txtp); - ubr = txtp->traffic_class == ATM_UBR; - unlimited = ubr && (!rate || rate <= -ATM_OC3_PCR || - rate >= ATM_OC3_PCR); - if (!unlimited) { - size = txtp->max_sdu*eni_dev->tx_mult/100; - if (size > MID_MAX_BUF_SIZE && txtp->max_sdu <= - MID_MAX_BUF_SIZE) - size = MID_MAX_BUF_SIZE; - } - else { - if (eni_dev->ubr) { - eni_vcc->tx = eni_dev->ubr; - txtp->pcr = ATM_OC3_PCR; - return 0; - } - size = UBR_BUFFER; - } - new_tx = !eni_vcc->tx; - mem = NULL; /* for gcc */ - if (!new_tx) tx = eni_vcc->tx; - else { - mem = eni_alloc_mem(eni_dev,&size); - if (!mem) return -ENOBUFS; - tx = alloc_tx(eni_dev,unlimited); - if (!tx) { - eni_free_mem(eni_dev,mem,size); - return -EBUSY; - } - DPRINTK("got chan %d\n",tx->index); - tx->reserved = tx->shaping = 0; - tx->send = mem; - tx->words = size >> 2; - skb_queue_head_init(&tx->backlog); - for (order = 0; size > (1 << (order+10)); order++); - eni_out((order << MID_SIZE_SHIFT) | - ((tx->send-eni_dev->ram) >> (MID_LOC_SKIP+2)), - MID_TX_PLACE(tx->index)); - tx->tx_pos = eni_in(MID_TX_DESCRSTART(tx->index)) & - MID_DESCR_START; - } - error = comp_tx(eni_dev,&rate,tx->reserved,&pre,&res,unlimited); - if (!error && txtp->min_pcr > rate) error = -EINVAL; - if (!error && txtp->max_pcr && txtp->max_pcr != ATM_MAX_PCR && - txtp->max_pcr < rate) error = -EINVAL; - if (!error && !ubr && rate > eni_dev->tx_bw+tx->reserved) - error = -EINVAL; - if (!error && set_rsv && !set_shp && rate < tx->shaping) - error = -EINVAL; - if (!error && !set_rsv && rate > tx->reserved && !ubr) - error = -EINVAL; - if (error) { - if (new_tx) { - tx->send = NULL; - eni_free_mem(eni_dev,mem,size); - } - return error; - } - txtp->pcr = rate; - if (set_rsv && !ubr) { - eni_dev->tx_bw += tx->reserved; - tx->reserved = rate; - eni_dev->tx_bw -= rate; - } - if (set_shp || (unlimited && new_tx)) { - if (unlimited && new_tx) eni_dev->ubr = tx; - tx->prescaler = pre; - tx->resolution = res; - tx->shaping = rate; - } - if (set_shp) eni_vcc->tx = tx; - DPRINTK("rsv %d shp %d\n",tx->reserved,tx->shaping); - return 0; -} - - -static int open_tx_first(struct atm_vcc *vcc) -{ - ENI_VCC(vcc)->tx = NULL; - if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; - ENI_VCC(vcc)->txing = 0; - return reserve_or_set_tx(vcc,&vcc->qos.txtp,1,1); -} - - -static int open_tx_second(struct atm_vcc *vcc) -{ - return 0; /* nothing to do */ -} - - -static void close_tx(struct atm_vcc *vcc) -{ - DECLARE_WAITQUEUE(wait,current); - struct eni_dev *eni_dev; - struct eni_vcc *eni_vcc; - - eni_vcc = ENI_VCC(vcc); - if (!eni_vcc->tx) return; - eni_dev = ENI_DEV(vcc->dev); - /* wait for TX queue to drain */ - DPRINTK("eni_close: waiting for TX ...\n"); - add_wait_queue(&eni_dev->tx_wait,&wait); - set_current_state(TASK_UNINTERRUPTIBLE); - for (;;) { - int txing; - - tasklet_disable(&eni_dev->task); - txing = skb_peek(&eni_vcc->tx->backlog) || eni_vcc->txing; - tasklet_enable(&eni_dev->task); - if (!txing) break; - DPRINTK("%d TX left\n",eni_vcc->txing); - schedule(); - set_current_state(TASK_UNINTERRUPTIBLE); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&eni_dev->tx_wait,&wait); - if (eni_vcc->tx != eni_dev->ubr) { - /* - * Looping a few times in here is probably far cheaper than - * keeping track of TX completions all the time, so let's poll - * a bit ... - */ - while (eni_in(MID_TX_RDPTR(eni_vcc->tx->index)) != - eni_in(MID_TX_DESCRSTART(eni_vcc->tx->index))) - schedule(); - eni_free_mem(eni_dev,eni_vcc->tx->send,eni_vcc->tx->words << 2); - eni_vcc->tx->send = NULL; - eni_dev->tx_bw += eni_vcc->tx->reserved; - } - eni_vcc->tx = NULL; -} - - -static int start_tx(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - int i; - - eni_dev = ENI_DEV(dev); - eni_dev->lost = 0; - eni_dev->tx_bw = ATM_OC3_PCR; - eni_dev->tx_mult = DEFAULT_TX_MULT; - init_waitqueue_head(&eni_dev->tx_wait); - eni_dev->ubr = NULL; - skb_queue_head_init(&eni_dev->tx_queue); - eni_out(0,MID_DMA_WR_TX); - for (i = 0; i < NR_CHAN; i++) { - eni_dev->tx[i].send = NULL; - eni_dev->tx[i].index = i; - } - return 0; -} - - -/*--------------------------------- common ----------------------------------*/ - - -#if 0 /* may become useful again when tuning things */ - -static void foo(void) -{ -printk(KERN_INFO - "tx_complete=%d,dma_complete=%d,queued=%d,requeued=%d,sub=%d,\n" - "backlogged=%d,rx_enqueued=%d,rx_dequeued=%d,putting=%d,pushed=%d\n", - tx_complete,dma_complete,queued,requeued,submitted,backlogged, - rx_enqueued,rx_dequeued,putting,pushed); -if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost); -} - -#endif - - -static void bug_int(struct atm_dev *dev,unsigned long reason) -{ - DPRINTK(">bug_int\n"); - if (reason & MID_DMA_ERR_ACK) - printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " - "error\n",dev->number); - if (reason & MID_TX_IDENT_MISM) - printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - ident " - "mismatch\n",dev->number); - if (reason & MID_TX_DMA_OVFL) - printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA " - "overflow\n",dev->number); - EVENT("---dump ends here---\n",0,0); - printk(KERN_NOTICE "---recent events---\n"); - event_dump(); -} - - -static irqreturn_t eni_int(int irq,void *dev_id) -{ - struct atm_dev *dev; - struct eni_dev *eni_dev; - u32 reason; - - DPRINTK(">eni_int\n"); - dev = dev_id; - eni_dev = ENI_DEV(dev); - reason = eni_in(MID_ISA); - DPRINTK(DEV_LABEL ": int 0x%lx\n",(unsigned long) reason); - /* - * Must handle these two right now, because reading ISA doesn't clear - * them, so they re-occur and we never make it to the tasklet. Since - * they're rare, we don't mind the occasional invocation of eni_tasklet - * with eni_dev->events == 0. - */ - if (reason & MID_STAT_OVFL) { - EVENT("stat overflow\n",0,0); - eni_dev->lost += eni_in(MID_STAT) & MID_OVFL_TRASH; - } - if (reason & MID_SUNI_INT) { - EVENT("SUNI int\n",0,0); - dev->phy->interrupt(dev); -#if 0 - foo(); -#endif - } - spin_lock(&eni_dev->lock); - eni_dev->events |= reason; - spin_unlock(&eni_dev->lock); - tasklet_schedule(&eni_dev->task); - return IRQ_HANDLED; -} - - -static void eni_tasklet(unsigned long data) -{ - struct atm_dev *dev = (struct atm_dev *) data; - struct eni_dev *eni_dev = ENI_DEV(dev); - unsigned long flags; - u32 events; - - DPRINTK("eni_tasklet (dev %p)\n",dev); - spin_lock_irqsave(&eni_dev->lock,flags); - events = xchg(&eni_dev->events,0); - spin_unlock_irqrestore(&eni_dev->lock,flags); - if (events & MID_RX_DMA_COMPLETE) { - EVENT("INT: RX DMA complete, starting dequeue_rx\n",0,0); - dequeue_rx(dev); - EVENT("dequeue_rx done, starting poll_rx\n",0,0); - poll_rx(dev); - EVENT("poll_rx done\n",0,0); - /* poll_tx ? */ - } - if (events & MID_SERVICE) { - EVENT("INT: service, starting get_service\n",0,0); - get_service(dev); - EVENT("get_service done, starting poll_rx\n",0,0); - poll_rx(dev); - EVENT("poll_rx done\n",0,0); - } - if (events & MID_TX_DMA_COMPLETE) { - EVENT("INT: TX DMA COMPLETE\n",0,0); - dequeue_tx(dev); - } - if (events & MID_TX_COMPLETE) { - EVENT("INT: TX COMPLETE\n",0,0); - tx_complete++; - wake_up(&eni_dev->tx_wait); - /* poll_rx ? */ - } - if (events & (MID_DMA_ERR_ACK | MID_TX_IDENT_MISM | MID_TX_DMA_OVFL)) { - EVENT("bug interrupt\n",0,0); - bug_int(dev,events); - } - poll_tx(dev); -} - - -/*--------------------------------- entries ---------------------------------*/ - - -static char * const media_name[] = { - "MMF", "SMF", "MMF", "03?", /* 0- 3 */ - "UTP", "05?", "06?", "07?", /* 4- 7 */ - "TAXI","09?", "10?", "11?", /* 8-11 */ - "12?", "13?", "14?", "15?", /* 12-15 */ - "MMF", "SMF", "18?", "19?", /* 16-19 */ - "UTP", "21?", "22?", "23?", /* 20-23 */ - "24?", "25?", "26?", "27?", /* 24-27 */ - "28?", "29?", "30?", "31?" /* 28-31 */ -}; - - -#define SET_SEPROM \ - ({ if (!error && !pci_error) { \ - pci_error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL,tonga); \ - udelay(10); /* 10 usecs */ \ - } }) -#define GET_SEPROM \ - ({ if (!error && !pci_error) { \ - pci_error = pci_read_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL,&tonga); \ - udelay(10); /* 10 usecs */ \ - } }) - - -static int get_esi_asic(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - unsigned char tonga; - int error,failed,pci_error; - int address,i,j; - - eni_dev = ENI_DEV(dev); - error = pci_error = 0; - tonga = SEPROM_MAGIC | SEPROM_DATA | SEPROM_CLK; - SET_SEPROM; - for (i = 0; i < ESI_LEN && !error && !pci_error; i++) { - /* start operation */ - tonga |= SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - tonga &= ~SEPROM_DATA; - SET_SEPROM; - tonga &= ~SEPROM_CLK; - SET_SEPROM; - /* send address */ - address = ((i+SEPROM_ESI_BASE) << 1)+1; - for (j = 7; j >= 0; j--) { - tonga = (address >> j) & 1 ? tonga | SEPROM_DATA : - tonga & ~SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - tonga &= ~SEPROM_CLK; - SET_SEPROM; - } - /* get ack */ - tonga |= SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - GET_SEPROM; - failed = tonga & SEPROM_DATA; - tonga &= ~SEPROM_CLK; - SET_SEPROM; - tonga |= SEPROM_DATA; - SET_SEPROM; - if (failed) error = -EIO; - else { - dev->esi[i] = 0; - for (j = 7; j >= 0; j--) { - dev->esi[i] <<= 1; - tonga |= SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - GET_SEPROM; - if (tonga & SEPROM_DATA) dev->esi[i] |= 1; - tonga &= ~SEPROM_CLK; - SET_SEPROM; - tonga |= SEPROM_DATA; - SET_SEPROM; - } - /* get ack */ - tonga |= SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - GET_SEPROM; - if (!(tonga & SEPROM_DATA)) error = -EIO; - tonga &= ~SEPROM_CLK; - SET_SEPROM; - tonga |= SEPROM_DATA; - SET_SEPROM; - } - /* stop operation */ - tonga &= ~SEPROM_DATA; - SET_SEPROM; - tonga |= SEPROM_CLK; - SET_SEPROM; - tonga |= SEPROM_DATA; - SET_SEPROM; - } - if (pci_error) { - printk(KERN_ERR DEV_LABEL "(itf %d): error reading ESI " - "(0x%02x)\n",dev->number,pci_error); - error = -EIO; - } - return error; -} - - -#undef SET_SEPROM -#undef GET_SEPROM - - -static int get_esi_fpga(struct atm_dev *dev, void __iomem *base) -{ - void __iomem *mac_base; - int i; - - mac_base = base+EPROM_SIZE-sizeof(struct midway_eprom); - for (i = 0; i < ESI_LEN; i++) dev->esi[i] = readb(mac_base+(i^3)); - return 0; -} - - -static int eni_do_init(struct atm_dev *dev) -{ - struct midway_eprom __iomem *eprom; - struct eni_dev *eni_dev; - struct pci_dev *pci_dev; - unsigned long real_base; - void __iomem *base; - int error,i,last; - - DPRINTK(">eni_init\n"); - dev->ci_range.vpi_bits = 0; - dev->ci_range.vci_bits = NR_VCI_LD; - dev->link_rate = ATM_OC3_PCR; - eni_dev = ENI_DEV(dev); - pci_dev = eni_dev->pci_dev; - real_base = pci_resource_start(pci_dev, 0); - eni_dev->irq = pci_dev->irq; - if ((error = pci_write_config_word(pci_dev,PCI_COMMAND, - PCI_COMMAND_MEMORY | - (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory " - "(0x%02x)\n",dev->number,error); - return -EIO; - } - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,", - dev->number,pci_dev->revision,real_base,eni_dev->irq); - if (!(base = ioremap(real_base,MAP_MAX_SIZE))) { - printk("\n"); - printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page " - "mapping\n",dev->number); - return -ENOMEM; - } - eni_dev->ioaddr = base; - eni_dev->base_diff = real_base - (unsigned long) base; - /* id may not be present in ASIC Tonga boards - check this @@@ */ - if (!eni_dev->asic) { - eprom = (base+EPROM_SIZE-sizeof(struct midway_eprom)); - if (readl(&eprom->magic) != ENI155_MAGIC) { - printk("\n"); - printk(KERN_ERR DEV_LABEL - "(itf %d): bad magic - expected 0x%x, got 0x%x\n", - dev->number, ENI155_MAGIC, - (unsigned)readl(&eprom->magic)); - error = -EINVAL; - goto unmap; - } - } - eni_dev->phy = base+PHY_BASE; - eni_dev->reg = base+REG_BASE; - eni_dev->ram = base+RAM_BASE; - last = MAP_MAX_SIZE-RAM_BASE; - for (i = last-RAM_INCREMENT; i >= 0; i -= RAM_INCREMENT) { - writel(0x55555555,eni_dev->ram+i); - if (readl(eni_dev->ram+i) != 0x55555555) last = i; - else { - writel(0xAAAAAAAA,eni_dev->ram+i); - if (readl(eni_dev->ram+i) != 0xAAAAAAAA) last = i; - else writel(i,eni_dev->ram+i); - } - } - for (i = 0; i < last; i += RAM_INCREMENT) - if (readl(eni_dev->ram+i) != i) break; - eni_dev->mem = i; - memset_io(eni_dev->ram,0,eni_dev->mem); - /* TODO: should shrink allocation now */ - printk("mem=%dkB (",eni_dev->mem >> 10); - /* TODO: check for non-SUNI, check for TAXI ? */ - if (!(eni_in(MID_RES_ID_MCON) & 0x200) != !eni_dev->asic) { - printk(")\n"); - printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n", - dev->number,(unsigned) eni_in(MID_RES_ID_MCON)); - error = -EINVAL; - goto unmap; - } - error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base); - if (error) - goto unmap; - for (i = 0; i < ESI_LEN; i++) - printk("%s%02X",i ? "-" : "",dev->esi[i]); - printk(")\n"); - printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number, - eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA", - media_name[eni_in(MID_RES_ID_MCON) & DAUGHTER_ID]); - - error = suni_init(dev); - if (error) - goto unmap; -out: - return error; -unmap: - iounmap(base); - goto out; -} - -static void eni_do_release(struct atm_dev *dev) -{ - struct eni_dev *ed = ENI_DEV(dev); - - dev->phy->stop(dev); - dev->phy = NULL; - iounmap(ed->ioaddr); -} - -static int eni_start(struct atm_dev *dev) -{ - struct eni_dev *eni_dev; - - void __iomem *buf; - unsigned long buffer_mem; - int error; - - DPRINTK(">eni_start\n"); - eni_dev = ENI_DEV(dev); - if (request_irq(eni_dev->irq,&eni_int,IRQF_SHARED,DEV_LABEL,dev)) { - printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", - dev->number,eni_dev->irq); - error = -EAGAIN; - goto out; - } - pci_set_master(eni_dev->pci_dev); - if ((error = pci_write_config_word(eni_dev->pci_dev,PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | - (eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" - "master (0x%02x)\n",dev->number,error); - goto free_irq; - } - if ((error = pci_write_config_byte(eni_dev->pci_dev,PCI_TONGA_CTRL, - END_SWAP_DMA))) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't set endian swap " - "(0x%02x)\n",dev->number,error); - goto free_irq; - } - /* determine addresses of internal tables */ - eni_dev->vci = eni_dev->ram; - eni_dev->rx_dma = eni_dev->ram+NR_VCI*16; - eni_dev->tx_dma = eni_dev->rx_dma+NR_DMA_RX*8; - eni_dev->service = eni_dev->tx_dma+NR_DMA_TX*8; - buf = eni_dev->service+NR_SERVICE*4; - DPRINTK("vci 0x%lx,rx 0x%lx, tx 0x%lx,srv 0x%lx,buf 0x%lx\n", - eni_dev->vci,eni_dev->rx_dma,eni_dev->tx_dma, - eni_dev->service,buf); - spin_lock_init(&eni_dev->lock); - tasklet_init(&eni_dev->task,eni_tasklet,(unsigned long) dev); - eni_dev->events = 0; - /* initialize memory management */ - buffer_mem = eni_dev->mem - (buf - eni_dev->ram); - eni_dev->free_list_size = buffer_mem/MID_MIN_BUF_SIZE/2; - eni_dev->free_list = kmalloc_objs(*eni_dev->free_list, - eni_dev->free_list_size + 1); - if (!eni_dev->free_list) { - printk(KERN_ERR DEV_LABEL "(itf %d): couldn't get free page\n", - dev->number); - error = -ENOMEM; - goto free_irq; - } - eni_dev->free_len = 0; - eni_put_free(eni_dev,buf,buffer_mem); - memset_io(eni_dev->vci,0,16*NR_VCI); /* clear VCI table */ - /* - * byte_addr free (k) - * 0x00000000 512 VCI table - * 0x00004000 496 RX DMA - * 0x00005000 492 TX DMA - * 0x00006000 488 service list - * 0x00007000 484 buffers - * 0x00080000 0 end (512kB) - */ - eni_out(0xffffffff,MID_IE); - error = start_tx(dev); - if (error) goto free_list; - error = start_rx(dev); - if (error) goto free_list; - error = dev->phy->start(dev); - if (error) goto free_list; - eni_out(eni_in(MID_MC_S) | (1 << MID_INT_SEL_SHIFT) | - MID_TX_LOCK_MODE | MID_DMA_ENABLE | MID_TX_ENABLE | MID_RX_ENABLE, - MID_MC_S); - /* Tonga uses SBus INTReq1 */ - (void) eni_in(MID_ISA); /* clear Midway interrupts */ - return 0; - -free_list: - kfree(eni_dev->free_list); - -free_irq: - free_irq(eni_dev->irq, dev); - -out: - return error; -} - - -static void eni_close(struct atm_vcc *vcc) -{ - DPRINTK(">eni_close\n"); - if (!ENI_VCC(vcc)) return; - clear_bit(ATM_VF_READY,&vcc->flags); - close_rx(vcc); - close_tx(vcc); - DPRINTK("eni_close: done waiting\n"); - /* deallocate memory */ - kfree(ENI_VCC(vcc)); - vcc->dev_data = NULL; - clear_bit(ATM_VF_ADDR,&vcc->flags); - /*foo();*/ -} - - -static int eni_open(struct atm_vcc *vcc) -{ - struct eni_vcc *eni_vcc; - int error; - short vpi = vcc->vpi; - int vci = vcc->vci; - - DPRINTK(">eni_open\n"); - EVENT("eni_open\n",0,0); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) - vcc->dev_data = NULL; - if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) - set_bit(ATM_VF_ADDR,&vcc->flags); - if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5) - return -EINVAL; - DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n",vcc->dev->number,vcc->vpi, - vcc->vci); - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) { - eni_vcc = kmalloc_obj(struct eni_vcc); - if (!eni_vcc) return -ENOMEM; - vcc->dev_data = eni_vcc; - eni_vcc->tx = NULL; /* for eni_close after open_rx */ - if ((error = open_rx_first(vcc))) { - eni_close(vcc); - return error; - } - if ((error = open_tx_first(vcc))) { - eni_close(vcc); - return error; - } - } - if (vci == ATM_VPI_UNSPEC || vpi == ATM_VCI_UNSPEC) return 0; - if ((error = open_rx_second(vcc))) { - eni_close(vcc); - return error; - } - if ((error = open_tx_second(vcc))) { - eni_close(vcc); - return error; - } - set_bit(ATM_VF_READY,&vcc->flags); - /* should power down SUNI while !ref_count @@@ */ - return 0; -} - - -static int eni_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flgs) -{ - struct eni_dev *eni_dev = ENI_DEV(vcc->dev); - struct eni_tx *tx = ENI_VCC(vcc)->tx; - struct sk_buff *skb; - int error,rate,rsv,shp; - - if (qos->txtp.traffic_class == ATM_NONE) return 0; - if (tx == eni_dev->ubr) return -EBADFD; - rate = atm_pcr_goal(&qos->txtp); - if (rate < 0) rate = -rate; - rsv = shp = 0; - if ((flgs & ATM_MF_DEC_RSV) && rate && rate < tx->reserved) rsv = 1; - if ((flgs & ATM_MF_INC_RSV) && (!rate || rate > tx->reserved)) rsv = 1; - if ((flgs & ATM_MF_DEC_SHP) && rate && rate < tx->shaping) shp = 1; - if ((flgs & ATM_MF_INC_SHP) && (!rate || rate > tx->shaping)) shp = 1; - if (!rsv && !shp) return 0; - error = reserve_or_set_tx(vcc,&qos->txtp,rsv,shp); - if (error) return error; - if (shp && !(flgs & ATM_MF_IMMED)) return 0; - /* - * Walk through the send buffer and patch the rate information in all - * segmentation buffer descriptors of this VCC. - */ - tasklet_disable(&eni_dev->task); - skb_queue_walk(&eni_dev->tx_queue, skb) { - void __iomem *dsc; - - if (ATM_SKB(skb)->vcc != vcc) continue; - dsc = tx->send+ENI_PRV_POS(skb)*4; - writel((readl(dsc) & ~(MID_SEG_RATE | MID_SEG_PR)) | - (tx->prescaler << MID_SEG_PR_SHIFT) | - (tx->resolution << MID_SEG_RATE_SHIFT), dsc); - } - tasklet_enable(&eni_dev->task); - return 0; -} - - -static int eni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - struct eni_dev *eni_dev = ENI_DEV(dev); - - if (cmd == ENI_MEMDUMP) { - if (!capable(CAP_NET_ADMIN)) return -EPERM; - printk(KERN_WARNING "Please use /proc/atm/" DEV_LABEL ":%d " - "instead of obsolete ioctl ENI_MEMDUMP\n",dev->number); - dump(dev); - return 0; - } - if (cmd == ENI_SETMULT) { - struct eni_multipliers mult; - - if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (copy_from_user(&mult, arg, - sizeof(struct eni_multipliers))) - return -EFAULT; - if ((mult.tx && mult.tx <= 100) || (mult.rx &&mult.rx <= 100) || - mult.tx > 65536 || mult.rx > 65536) - return -EINVAL; - if (mult.tx) eni_dev->tx_mult = mult.tx; - if (mult.rx) eni_dev->rx_mult = mult.rx; - return 0; - } - if (cmd == ATM_SETCIRANGE) { - struct atm_cirange ci; - - if (copy_from_user(&ci, arg,sizeof(struct atm_cirange))) - return -EFAULT; - if ((ci.vpi_bits == 0 || ci.vpi_bits == ATM_CI_MAX) && - (ci.vci_bits == NR_VCI_LD || ci.vpi_bits == ATM_CI_MAX)) - return 0; - return -EINVAL; - } - if (!dev->phy->ioctl) return -ENOIOCTLCMD; - return dev->phy->ioctl(dev,cmd,arg); -} - -static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb) -{ - enum enq_res res; - - DPRINTK(">eni_send\n"); - if (!ENI_VCC(vcc)->tx) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return -EINVAL; - } - if (!skb) { - printk(KERN_CRIT "!skb in eni_send ?\n"); - if (vcc->pop) vcc->pop(vcc,skb); - return -EINVAL; - } - if (vcc->qos.aal == ATM_AAL0) { - if (skb->len != ATM_CELL_SIZE-1) { - if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb); - return -EINVAL; - } - *(u32 *) skb->data = htonl(*(u32 *) skb->data); - } - submitted++; - ATM_SKB(skb)->vcc = vcc; - tasklet_disable_in_atomic(&ENI_DEV(vcc->dev)->task); - res = do_tx(skb); - tasklet_enable(&ENI_DEV(vcc->dev)->task); - if (res == enq_ok) return 0; - skb_queue_tail(&ENI_VCC(vcc)->tx->backlog,skb); - backlogged++; - tasklet_schedule(&ENI_DEV(vcc->dev)->task); - return 0; -} - -static void eni_phy_put(struct atm_dev *dev,unsigned char value, - unsigned long addr) -{ - writel(value,ENI_DEV(dev)->phy+addr*4); -} - - - -static unsigned char eni_phy_get(struct atm_dev *dev,unsigned long addr) -{ - return readl(ENI_DEV(dev)->phy+addr*4); -} - - -static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page) -{ - struct sock *s; - static const char *signal[] = { "LOST","unknown","okay" }; - struct eni_dev *eni_dev = ENI_DEV(dev); - struct atm_vcc *vcc; - int left,i; - - left = *pos; - if (!left) - return sprintf(page,DEV_LABEL "(itf %d) signal %s, %dkB, " - "%d cps remaining\n",dev->number,signal[(int) dev->signal], - eni_dev->mem >> 10,eni_dev->tx_bw); - if (!--left) - return sprintf(page,"%4sBursts: TX" -#if !defined(CONFIG_ATM_ENI_BURST_TX_16W) && \ - !defined(CONFIG_ATM_ENI_BURST_TX_8W) && \ - !defined(CONFIG_ATM_ENI_BURST_TX_4W) && \ - !defined(CONFIG_ATM_ENI_BURST_TX_2W) - " none" -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_16W - " 16W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_8W - " 8W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_4W - " 4W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_TX_2W - " 2W" -#endif - ", RX" -#if !defined(CONFIG_ATM_ENI_BURST_RX_16W) && \ - !defined(CONFIG_ATM_ENI_BURST_RX_8W) && \ - !defined(CONFIG_ATM_ENI_BURST_RX_4W) && \ - !defined(CONFIG_ATM_ENI_BURST_RX_2W) - " none" -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_16W - " 16W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_8W - " 8W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_4W - " 4W" -#endif -#ifdef CONFIG_ATM_ENI_BURST_RX_2W - " 2W" -#endif -#ifndef CONFIG_ATM_ENI_TUNE_BURST - " (default)" -#endif - "\n",""); - if (!--left) - return sprintf(page,"%4sBuffer multipliers: tx %d%%, rx %d%%\n", - "",eni_dev->tx_mult,eni_dev->rx_mult); - for (i = 0; i < NR_CHAN; i++) { - struct eni_tx *tx = eni_dev->tx+i; - - if (!tx->send) continue; - if (!--left) { - return sprintf(page, "tx[%d]: 0x%lx-0x%lx " - "(%6ld bytes), rsv %d cps, shp %d cps%s\n",i, - (unsigned long) (tx->send - eni_dev->ram), - tx->send-eni_dev->ram+tx->words*4-1,tx->words*4, - tx->reserved,tx->shaping, - tx == eni_dev->ubr ? " (UBR)" : ""); - } - if (--left) continue; - return sprintf(page,"%10sbacklog %u packets\n","", - skb_queue_len(&tx->backlog)); - } - read_lock(&vcc_sklist_lock); - for(i = 0; i < VCC_HTABLE_SIZE; ++i) { - struct hlist_head *head = &vcc_hash[i]; - - sk_for_each(s, head) { - struct eni_vcc *eni_vcc; - int length; - - vcc = atm_sk(s); - if (vcc->dev != dev) - continue; - eni_vcc = ENI_VCC(vcc); - if (--left) continue; - length = sprintf(page,"vcc %4d: ",vcc->vci); - if (eni_vcc->rx) { - length += sprintf(page+length, "0x%lx-0x%lx " - "(%6ld bytes)", - (unsigned long) (eni_vcc->recv - eni_dev->ram), - eni_vcc->recv-eni_dev->ram+eni_vcc->words*4-1, - eni_vcc->words*4); - if (eni_vcc->tx) length += sprintf(page+length,", "); - } - if (eni_vcc->tx) - length += sprintf(page+length,"tx[%d], txing %d bytes", - eni_vcc->tx->index,eni_vcc->txing); - page[length] = '\n'; - read_unlock(&vcc_sklist_lock); - return length+1; - } - } - read_unlock(&vcc_sklist_lock); - for (i = 0; i < eni_dev->free_len; i++) { - struct eni_free *fe = eni_dev->free_list+i; - unsigned long offset; - - if (--left) continue; - offset = (unsigned long) eni_dev->ram+eni_dev->base_diff; - return sprintf(page,"free %p-%p (%6d bytes)\n", - fe->start-offset,fe->start-offset+(1 << fe->order)-1, - 1 << fe->order); - } - return 0; -} - - -static const struct atmdev_ops ops = { - .open = eni_open, - .close = eni_close, - .ioctl = eni_ioctl, - .send = eni_send, - .phy_put = eni_phy_put, - .phy_get = eni_phy_get, - .change_qos = eni_change_qos, - .proc_read = eni_proc_read -}; - - -static int eni_init_one(struct pci_dev *pci_dev, - const struct pci_device_id *ent) -{ - struct atm_dev *dev; - struct eni_dev *eni_dev; - struct eni_zero *zero; - int rc; - - rc = pci_enable_device(pci_dev); - if (rc < 0) - goto out; - - rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)); - if (rc < 0) - goto err_disable; - - rc = -ENOMEM; - eni_dev = kmalloc_obj(struct eni_dev); - if (!eni_dev) - goto err_disable; - - zero = &eni_dev->zero; - zero->addr = dma_alloc_coherent(&pci_dev->dev, - ENI_ZEROES_SIZE, &zero->dma, GFP_KERNEL); - if (!zero->addr) - goto err_kfree; - - dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &ops, -1, NULL); - if (!dev) - goto err_free_consistent; - - dev->dev_data = eni_dev; - pci_set_drvdata(pci_dev, dev); - eni_dev->pci_dev = pci_dev; - eni_dev->asic = ent->driver_data; - - rc = eni_do_init(dev); - if (rc < 0) - goto err_unregister; - - rc = eni_start(dev); - if (rc < 0) - goto err_eni_release; - - eni_dev->more = eni_boards; - eni_boards = dev; -out: - return rc; - -err_eni_release: - dev->phy = NULL; - iounmap(ENI_DEV(dev)->ioaddr); -err_unregister: - atm_dev_deregister(dev); -err_free_consistent: - dma_free_coherent(&pci_dev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); -err_kfree: - kfree(eni_dev); -err_disable: - pci_disable_device(pci_dev); - goto out; -} - - -static const struct pci_device_id eni_pci_tbl[] = { - { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_FPGA), 0 /* FPGA */ }, - { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_ASIC), 1 /* ASIC */ }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci,eni_pci_tbl); - - -static void eni_remove_one(struct pci_dev *pdev) -{ - struct atm_dev *dev = pci_get_drvdata(pdev); - struct eni_dev *ed = ENI_DEV(dev); - struct eni_zero *zero = &ed->zero; - - eni_do_release(dev); - atm_dev_deregister(dev); - dma_free_coherent(&pdev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); - kfree(ed); - pci_disable_device(pdev); -} - - -static struct pci_driver eni_driver = { - .name = DEV_LABEL, - .id_table = eni_pci_tbl, - .probe = eni_init_one, - .remove = eni_remove_one, -}; - - -static int __init eni_init(void) -{ - struct sk_buff *skb; /* dummy for sizeof */ - - BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct eni_skb_prv)); - return pci_register_driver(&eni_driver); -} - - -module_init(eni_init); -/* @@@ since exit routine not defined, this module can not be unloaded */ - -MODULE_DESCRIPTION("Efficient Networks ENI155P ATM NIC driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c deleted file mode 100644 index 2423eed506c1..000000000000 --- a/drivers/atm/fore200e.c +++ /dev/null @@ -1,3012 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - A FORE Systems 200E-series driver for ATM on Linux. - Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003. - - Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). - - This driver simultaneously supports PCA-200E and SBA-200E adapters - on i386, alpha (untested), powerpc, sparc and sparc64 architectures. - -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SBUS -#include -#include -#include -#include -#include -#endif - -#if defined(CONFIG_ATM_FORE200E_USE_TASKLET) /* defer interrupt work to a tasklet */ -#define FORE200E_USE_TASKLET -#endif - -#if 0 /* enable the debugging code of the buffer supply queues */ -#define FORE200E_BSQ_DEBUG -#endif - -#if 1 /* ensure correct handling of 52-byte AAL0 SDUs expected by atmdump-like apps */ -#define FORE200E_52BYTE_AAL0_SDU -#endif - -#include "fore200e.h" -#include "suni.h" - -#define FORE200E_VERSION "0.3e" - -#define FORE200E "fore200e: " - -#if 0 /* override .config */ -#define CONFIG_ATM_FORE200E_DEBUG 1 -#endif -#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) -#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ - printk(FORE200E format, ##args); } while (0) -#else -#define DPRINTK(level, format, args...) do {} while (0) -#endif - - -#define FORE200E_ALIGN(addr, alignment) \ - ((((unsigned long)(addr) + (alignment - 1)) & ~(alignment - 1)) - (unsigned long)(addr)) - -#define FORE200E_DMA_INDEX(dma_addr, type, index) ((dma_addr) + (index) * sizeof(type)) - -#define FORE200E_INDEX(virt_addr, type, index) (&((type *)(virt_addr))[ index ]) - -#define FORE200E_NEXT_ENTRY(index, modulo) (index = ((index) + 1) % (modulo)) - -#if 1 -#define ASSERT(expr) if (!(expr)) { \ - printk(FORE200E "assertion failed! %s[%d]: %s\n", \ - __func__, __LINE__, #expr); \ - panic(FORE200E "%s", __func__); \ - } -#else -#define ASSERT(expr) do {} while (0) -#endif - - -static const struct atmdev_ops fore200e_ops; - -MODULE_AUTHOR("Christophe Lizzi - credits to Uwe Dannowski and Heikki Vatiainen"); -MODULE_DESCRIPTION("FORE Systems 200E-series ATM driver - version " FORE200E_VERSION); - -static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { - { BUFFER_S1_NBR, BUFFER_L1_NBR }, - { BUFFER_S2_NBR, BUFFER_L2_NBR } -}; - -static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] = { - { BUFFER_S1_SIZE, BUFFER_L1_SIZE }, - { BUFFER_S2_SIZE, BUFFER_L2_SIZE } -}; - - -#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) -static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" }; -#endif - - -#if 0 /* currently unused */ -static int -fore200e_fore2atm_aal(enum fore200e_aal aal) -{ - switch(aal) { - case FORE200E_AAL0: return ATM_AAL0; - case FORE200E_AAL34: return ATM_AAL34; - case FORE200E_AAL5: return ATM_AAL5; - } - - return -EINVAL; -} -#endif - - -static enum fore200e_aal -fore200e_atm2fore_aal(int aal) -{ - switch(aal) { - case ATM_AAL0: return FORE200E_AAL0; - case ATM_AAL34: return FORE200E_AAL34; - case ATM_AAL1: - case ATM_AAL2: - case ATM_AAL5: return FORE200E_AAL5; - } - - return -EINVAL; -} - - -static char* -fore200e_irq_itoa(int irq) -{ - static char str[8]; - sprintf(str, "%d", irq); - return str; -} - - -/* allocate and align a chunk of memory intended to hold the data behing exchanged - between the driver and the adapter (using streaming DVMA) */ - -static int -fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction) -{ - unsigned long offset = 0; - - if (alignment <= sizeof(int)) - alignment = 0; - - chunk->alloc_size = size + alignment; - chunk->direction = direction; - - chunk->alloc_addr = kzalloc(chunk->alloc_size, GFP_KERNEL); - if (chunk->alloc_addr == NULL) - return -ENOMEM; - - if (alignment > 0) - offset = FORE200E_ALIGN(chunk->alloc_addr, alignment); - - chunk->align_addr = chunk->alloc_addr + offset; - - chunk->dma_addr = dma_map_single(fore200e->dev, chunk->align_addr, - size, direction); - if (dma_mapping_error(fore200e->dev, chunk->dma_addr)) { - kfree(chunk->alloc_addr); - return -ENOMEM; - } - return 0; -} - - -/* free a chunk of memory */ - -static void -fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) -{ - dma_unmap_single(fore200e->dev, chunk->dma_addr, chunk->dma_size, - chunk->direction); - kfree(chunk->alloc_addr); -} - -/* - * Allocate a DMA consistent chunk of memory intended to act as a communication - * mechanism (to hold descriptors, status, queues, etc.) shared by the driver - * and the adapter. - */ -static int -fore200e_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk, - int size, int nbr, int alignment) -{ - /* returned chunks are page-aligned */ - chunk->alloc_size = size * nbr; - chunk->alloc_addr = dma_alloc_coherent(fore200e->dev, chunk->alloc_size, - &chunk->dma_addr, GFP_KERNEL); - if (!chunk->alloc_addr) - return -ENOMEM; - chunk->align_addr = chunk->alloc_addr; - return 0; -} - -/* - * Free a DMA consistent chunk of memory. - */ -static void -fore200e_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) -{ - dma_free_coherent(fore200e->dev, chunk->alloc_size, chunk->alloc_addr, - chunk->dma_addr); -} - -static void -fore200e_spin(int msecs) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(msecs); - while (time_before(jiffies, timeout)); -} - - -static int -fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(msecs); - int ok; - - mb(); - do { - if ((ok = (*addr == val)) || (*addr & STATUS_ERROR)) - break; - - } while (time_before(jiffies, timeout)); - -#if 1 - if (!ok) { - printk(FORE200E "cmd polling failed, got status 0x%08x, expected 0x%08x\n", - *addr, val); - } -#endif - - return ok; -} - - -static int -fore200e_io_poll(struct fore200e* fore200e, volatile u32 __iomem *addr, u32 val, int msecs) -{ - unsigned long timeout = jiffies + msecs_to_jiffies(msecs); - int ok; - - do { - if ((ok = (fore200e->bus->read(addr) == val))) - break; - - } while (time_before(jiffies, timeout)); - -#if 1 - if (!ok) { - printk(FORE200E "I/O polling failed, got status 0x%08x, expected 0x%08x\n", - fore200e->bus->read(addr), val); - } -#endif - - return ok; -} - - -static void -fore200e_free_rx_buf(struct fore200e* fore200e) -{ - int scheme, magn, nbr; - struct buffer* buffer; - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { - - if ((buffer = fore200e->host_bsq[ scheme ][ magn ].buffer) != NULL) { - - for (nbr = 0; nbr < fore200e_rx_buf_nbr[ scheme ][ magn ]; nbr++) { - - struct chunk* data = &buffer[ nbr ].data; - - if (data->alloc_addr != NULL) - fore200e_chunk_free(fore200e, data); - } - } - } - } -} - - -static void -fore200e_uninit_bs_queue(struct fore200e* fore200e) -{ - int scheme, magn; - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { - - struct chunk* status = &fore200e->host_bsq[ scheme ][ magn ].status; - struct chunk* rbd_block = &fore200e->host_bsq[ scheme ][ magn ].rbd_block; - - if (status->alloc_addr) - fore200e_dma_chunk_free(fore200e, status); - - if (rbd_block->alloc_addr) - fore200e_dma_chunk_free(fore200e, rbd_block); - } - } -} - - -static int -fore200e_reset(struct fore200e* fore200e, int diag) -{ - int ok; - - fore200e->cp_monitor = fore200e->virt_base + FORE200E_CP_MONITOR_OFFSET; - - fore200e->bus->write(BSTAT_COLD_START, &fore200e->cp_monitor->bstat); - - fore200e->bus->reset(fore200e); - - if (diag) { - ok = fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_SELFTEST_OK, 1000); - if (ok == 0) { - - printk(FORE200E "device %s self-test failed\n", fore200e->name); - return -ENODEV; - } - - printk(FORE200E "device %s self-test passed\n", fore200e->name); - - fore200e->state = FORE200E_STATE_RESET; - } - - return 0; -} - - -static void -fore200e_shutdown(struct fore200e* fore200e) -{ - printk(FORE200E "removing device %s at 0x%lx, IRQ %s\n", - fore200e->name, fore200e->phys_base, - fore200e_irq_itoa(fore200e->irq)); - - if (fore200e->state > FORE200E_STATE_RESET) { - /* first, reset the board to prevent further interrupts or data transfers */ - fore200e_reset(fore200e, 0); - } - - /* then, release all allocated resources */ - switch(fore200e->state) { - - case FORE200E_STATE_COMPLETE: - kfree(fore200e->stats); - - fallthrough; - case FORE200E_STATE_IRQ: - free_irq(fore200e->irq, fore200e->atm_dev); -#ifdef FORE200E_USE_TASKLET - tasklet_kill(&fore200e->tx_tasklet); - tasklet_kill(&fore200e->rx_tasklet); -#endif - - fallthrough; - case FORE200E_STATE_ALLOC_BUF: - fore200e_free_rx_buf(fore200e); - - fallthrough; - case FORE200E_STATE_INIT_BSQ: - fore200e_uninit_bs_queue(fore200e); - - fallthrough; - case FORE200E_STATE_INIT_RXQ: - fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.status); - fore200e_dma_chunk_free(fore200e, &fore200e->host_rxq.rpd); - - fallthrough; - case FORE200E_STATE_INIT_TXQ: - fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.status); - fore200e_dma_chunk_free(fore200e, &fore200e->host_txq.tpd); - - fallthrough; - case FORE200E_STATE_INIT_CMDQ: - fore200e_dma_chunk_free(fore200e, &fore200e->host_cmdq.status); - - fallthrough; - case FORE200E_STATE_INITIALIZE: - /* nothing to do for that state */ - - case FORE200E_STATE_START_FW: - /* nothing to do for that state */ - - case FORE200E_STATE_RESET: - /* nothing to do for that state */ - - case FORE200E_STATE_MAP: - fore200e->bus->unmap(fore200e); - - fallthrough; - case FORE200E_STATE_CONFIGURE: - /* nothing to do for that state */ - - case FORE200E_STATE_REGISTER: - /* XXX shouldn't we *start* by deregistering the device? */ - atm_dev_deregister(fore200e->atm_dev); - - fallthrough; - case FORE200E_STATE_BLANK: - /* nothing to do for that state */ - break; - } -} - - -#ifdef CONFIG_PCI - -static u32 fore200e_pca_read(volatile u32 __iomem *addr) -{ - /* on big-endian hosts, the board is configured to convert - the endianess of slave RAM accesses */ - return le32_to_cpu(readl(addr)); -} - - -static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr) -{ - /* on big-endian hosts, the board is configured to convert - the endianess of slave RAM accesses */ - writel(cpu_to_le32(val), addr); -} - -static int -fore200e_pca_irq_check(struct fore200e* fore200e) -{ - /* this is a 1 bit register */ - int irq_posted = readl(fore200e->regs.pca.psr); - -#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG == 2) - if (irq_posted && (readl(fore200e->regs.pca.hcr) & PCA200E_HCR_OUTFULL)) { - DPRINTK(2,"FIFO OUT full, device %d\n", fore200e->atm_dev->number); - } -#endif - - return irq_posted; -} - - -static void -fore200e_pca_irq_ack(struct fore200e* fore200e) -{ - writel(PCA200E_HCR_CLRINTR, fore200e->regs.pca.hcr); -} - - -static void -fore200e_pca_reset(struct fore200e* fore200e) -{ - writel(PCA200E_HCR_RESET, fore200e->regs.pca.hcr); - fore200e_spin(10); - writel(0, fore200e->regs.pca.hcr); -} - - -static int fore200e_pca_map(struct fore200e* fore200e) -{ - DPRINTK(2, "device %s being mapped in memory\n", fore200e->name); - - fore200e->virt_base = ioremap(fore200e->phys_base, PCA200E_IOSPACE_LENGTH); - - if (fore200e->virt_base == NULL) { - printk(FORE200E "can't map device %s\n", fore200e->name); - return -EFAULT; - } - - DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); - - /* gain access to the PCA specific registers */ - fore200e->regs.pca.hcr = fore200e->virt_base + PCA200E_HCR_OFFSET; - fore200e->regs.pca.imr = fore200e->virt_base + PCA200E_IMR_OFFSET; - fore200e->regs.pca.psr = fore200e->virt_base + PCA200E_PSR_OFFSET; - - fore200e->state = FORE200E_STATE_MAP; - return 0; -} - - -static void -fore200e_pca_unmap(struct fore200e* fore200e) -{ - DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); - - if (fore200e->virt_base != NULL) - iounmap(fore200e->virt_base); -} - - -static int fore200e_pca_configure(struct fore200e *fore200e) -{ - struct pci_dev *pci_dev = to_pci_dev(fore200e->dev); - u8 master_ctrl, latency; - - DPRINTK(2, "device %s being configured\n", fore200e->name); - - if ((pci_dev->irq == 0) || (pci_dev->irq == 0xFF)) { - printk(FORE200E "incorrect IRQ setting - misconfigured PCI-PCI bridge?\n"); - return -EIO; - } - - pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); - - master_ctrl = master_ctrl -#if defined(__BIG_ENDIAN) - /* request the PCA board to convert the endianess of slave RAM accesses */ - | PCA200E_CTRL_CONVERT_ENDIAN -#endif -#if 0 - | PCA200E_CTRL_DIS_CACHE_RD - | PCA200E_CTRL_DIS_WRT_INVAL - | PCA200E_CTRL_ENA_CONT_REQ_MODE - | PCA200E_CTRL_2_CACHE_WRT_INVAL -#endif - | PCA200E_CTRL_LARGE_PCI_BURSTS; - - pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); - - /* raise latency from 32 (default) to 192, as this seems to prevent NIC - lockups (under heavy rx loads) due to continuous 'FIFO OUT full' condition. - this may impact the performances of other PCI devices on the same bus, though */ - latency = 192; - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); - - fore200e->state = FORE200E_STATE_CONFIGURE; - return 0; -} - - -static int __init -fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; - struct prom_opcode opcode; - int ok; - u32 prom_dma; - - FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); - - opcode.opcode = OPCODE_GET_PROM; - opcode.pad = 0; - - prom_dma = dma_map_single(fore200e->dev, prom, sizeof(struct prom_data), - DMA_FROM_DEVICE); - if (dma_mapping_error(fore200e->dev, prom_dma)) - return -ENOMEM; - - fore200e->bus->write(prom_dma, &entry->cp_entry->cmd.prom_block.prom_haddr); - - *entry->status = STATUS_PENDING; - - fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.prom_block.opcode); - - ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); - - *entry->status = STATUS_FREE; - - dma_unmap_single(fore200e->dev, prom_dma, sizeof(struct prom_data), DMA_FROM_DEVICE); - - if (ok == 0) { - printk(FORE200E "unable to get PROM data from device %s\n", fore200e->name); - return -EIO; - } - -#if defined(__BIG_ENDIAN) - -#define swap_here(addr) (*((u32*)(addr)) = swab32( *((u32*)(addr)) )) - - /* MAC address is stored as little-endian */ - swap_here(&prom->mac_addr[0]); - swap_here(&prom->mac_addr[4]); -#endif - - return 0; -} - - -static int -fore200e_pca_proc_read(struct fore200e* fore200e, char *page) -{ - struct pci_dev *pci_dev = to_pci_dev(fore200e->dev); - - return sprintf(page, " PCI bus/slot/function:\t%d/%d/%d\n", - pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn)); -} - -static const struct fore200e_bus fore200e_pci_ops = { - .model_name = "PCA-200E", - .proc_name = "pca200e", - .descr_alignment = 32, - .buffer_alignment = 4, - .status_alignment = 32, - .read = fore200e_pca_read, - .write = fore200e_pca_write, - .configure = fore200e_pca_configure, - .map = fore200e_pca_map, - .reset = fore200e_pca_reset, - .prom_read = fore200e_pca_prom_read, - .unmap = fore200e_pca_unmap, - .irq_check = fore200e_pca_irq_check, - .irq_ack = fore200e_pca_irq_ack, - .proc_read = fore200e_pca_proc_read, -}; -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS - -static u32 fore200e_sba_read(volatile u32 __iomem *addr) -{ - return sbus_readl(addr); -} - -static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr) -{ - sbus_writel(val, addr); -} - -static void fore200e_sba_irq_enable(struct fore200e *fore200e) -{ - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr); -} - -static int fore200e_sba_irq_check(struct fore200e *fore200e) -{ - return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ; -} - -static void fore200e_sba_irq_ack(struct fore200e *fore200e) -{ - u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY; - fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr); -} - -static void fore200e_sba_reset(struct fore200e *fore200e) -{ - fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr); - fore200e_spin(10); - fore200e->bus->write(0, fore200e->regs.sba.hcr); -} - -static int __init fore200e_sba_map(struct fore200e *fore200e) -{ - struct platform_device *op = to_platform_device(fore200e->dev); - unsigned int bursts; - - /* gain access to the SBA specific registers */ - fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); - fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); - fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); - fore200e->virt_base = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM"); - - if (!fore200e->virt_base) { - printk(FORE200E "unable to map RAM of device %s\n", fore200e->name); - return -EFAULT; - } - - DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); - - fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */ - - /* get the supported DVMA burst sizes */ - bursts = of_getintprop_default(op->dev.of_node->parent, "burst-sizes", 0x00); - - if (sbus_can_dma_64bit()) - sbus_set_sbus64(&op->dev, bursts); - - fore200e->state = FORE200E_STATE_MAP; - return 0; -} - -static void fore200e_sba_unmap(struct fore200e *fore200e) -{ - struct platform_device *op = to_platform_device(fore200e->dev); - - of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH); - of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH); - of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH); - of_iounmap(&op->resource[3], fore200e->virt_base, SBA200E_RAM_LENGTH); -} - -static int __init fore200e_sba_configure(struct fore200e *fore200e) -{ - fore200e->state = FORE200E_STATE_CONFIGURE; - return 0; -} - -static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom) -{ - struct platform_device *op = to_platform_device(fore200e->dev); - const u8 *prop; - int len; - - prop = of_get_property(op->dev.of_node, "madaddrlo2", &len); - if (!prop) - return -ENODEV; - memcpy(&prom->mac_addr[4], prop, 4); - - prop = of_get_property(op->dev.of_node, "madaddrhi4", &len); - if (!prop) - return -ENODEV; - memcpy(&prom->mac_addr[2], prop, 4); - - prom->serial_number = of_getintprop_default(op->dev.of_node, - "serialnumber", 0); - prom->hw_revision = of_getintprop_default(op->dev.of_node, - "promversion", 0); - - return 0; -} - -static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page) -{ - struct platform_device *op = to_platform_device(fore200e->dev); - const struct linux_prom_registers *regs; - - regs = of_get_property(op->dev.of_node, "reg", NULL); - - return sprintf(page, " SBUS slot/device:\t\t%d/'%pOFn'\n", - (regs ? regs->which_io : 0), op->dev.of_node); -} - -static const struct fore200e_bus fore200e_sbus_ops = { - .model_name = "SBA-200E", - .proc_name = "sba200e", - .descr_alignment = 32, - .buffer_alignment = 64, - .status_alignment = 32, - .read = fore200e_sba_read, - .write = fore200e_sba_write, - .configure = fore200e_sba_configure, - .map = fore200e_sba_map, - .reset = fore200e_sba_reset, - .prom_read = fore200e_sba_prom_read, - .unmap = fore200e_sba_unmap, - .irq_enable = fore200e_sba_irq_enable, - .irq_check = fore200e_sba_irq_check, - .irq_ack = fore200e_sba_irq_ack, - .proc_read = fore200e_sba_proc_read, -}; -#endif /* CONFIG_SBUS */ - -static void -fore200e_tx_irq(struct fore200e* fore200e) -{ - struct host_txq* txq = &fore200e->host_txq; - struct host_txq_entry* entry; - struct atm_vcc* vcc; - struct fore200e_vc_map* vc_map; - - if (fore200e->host_txq.txing == 0) - return; - - for (;;) { - - entry = &txq->host_entry[ txq->tail ]; - - if ((*entry->status & STATUS_COMPLETE) == 0) { - break; - } - - DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vc_map = %p, skb = %p\n", - entry, txq->tail, entry->vc_map, entry->skb); - - /* free copy of misaligned data */ - kfree(entry->data); - - /* remove DMA mapping */ - dma_unmap_single(fore200e->dev, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, - DMA_TO_DEVICE); - - vc_map = entry->vc_map; - - /* vcc closed since the time the entry was submitted for tx? */ - if ((vc_map->vcc == NULL) || - (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) { - - DPRINTK(1, "no ready vcc found for PDU sent on device %d\n", - fore200e->atm_dev->number); - - dev_kfree_skb_any(entry->skb); - } - else { - ASSERT(vc_map->vcc); - - /* vcc closed then immediately re-opened? */ - if (vc_map->incarn != entry->incarn) { - - /* when a vcc is closed, some PDUs may be still pending in the tx queue. - if the same vcc is immediately re-opened, those pending PDUs must - not be popped after the completion of their emission, as they refer - to the prior incarnation of that vcc. otherwise, sk_atm(vcc)->sk_wmem_alloc - would be decremented by the size of the (unrelated) skb, possibly - leading to a negative sk->sk_wmem_alloc count, ultimately freezing the vcc. - we thus bind the tx entry to the current incarnation of the vcc - when the entry is submitted for tx. When the tx later completes, - if the incarnation number of the tx entry does not match the one - of the vcc, then this implies that the vcc has been closed then re-opened. - we thus just drop the skb here. */ - - DPRINTK(1, "vcc closed-then-re-opened; dropping PDU sent on device %d\n", - fore200e->atm_dev->number); - - dev_kfree_skb_any(entry->skb); - } - else { - vcc = vc_map->vcc; - ASSERT(vcc); - - /* notify tx completion */ - if (vcc->pop) { - vcc->pop(vcc, entry->skb); - } - else { - dev_kfree_skb_any(entry->skb); - } - - /* check error condition */ - if (*entry->status & STATUS_ERROR) - atomic_inc(&vcc->stats->tx_err); - else - atomic_inc(&vcc->stats->tx); - } - } - - *entry->status = STATUS_FREE; - - fore200e->host_txq.txing--; - - FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX); - } -} - - -#ifdef FORE200E_BSQ_DEBUG -int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn) -{ - struct buffer* buffer; - int count = 0; - - buffer = bsq->freebuf; - while (buffer) { - - if (buffer->supplied) { - printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n", - where, scheme, magn, buffer->index); - } - - if (buffer->magn != magn) { - printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n", - where, scheme, magn, buffer->index, buffer->magn); - } - - if (buffer->scheme != scheme) { - printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n", - where, scheme, magn, buffer->index, buffer->scheme); - } - - if ((buffer->index < 0) || (buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ])) { - printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n", - where, scheme, magn, buffer->index); - } - - count++; - buffer = buffer->next; - } - - if (count != bsq->freebuf_count) { - printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n", - where, scheme, magn, count, bsq->freebuf_count); - } - return 0; -} -#endif - - -static void -fore200e_supply(struct fore200e* fore200e) -{ - int scheme, magn, i; - - struct host_bsq* bsq; - struct host_bsq_entry* entry; - struct buffer* buffer; - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { - - bsq = &fore200e->host_bsq[ scheme ][ magn ]; - -#ifdef FORE200E_BSQ_DEBUG - bsq_audit(1, bsq, scheme, magn); -#endif - while (bsq->freebuf_count >= RBD_BLK_SIZE) { - - DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n", - RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count); - - entry = &bsq->host_entry[ bsq->head ]; - - for (i = 0; i < RBD_BLK_SIZE; i++) { - - /* take the first buffer in the free buffer list */ - buffer = bsq->freebuf; - if (!buffer) { - printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n", - scheme, magn, bsq->freebuf_count); - return; - } - bsq->freebuf = buffer->next; - -#ifdef FORE200E_BSQ_DEBUG - if (buffer->supplied) - printk(FORE200E "queue %d.%d, buffer %lu already supplied\n", - scheme, magn, buffer->index); - buffer->supplied = 1; -#endif - entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; - entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); - } - - FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS); - - /* decrease accordingly the number of free rx buffers */ - bsq->freebuf_count -= RBD_BLK_SIZE; - - *entry->status = STATUS_PENDING; - fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); - } - } - } -} - - -static int -fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rpd) -{ - struct sk_buff* skb; - struct buffer* buffer; - struct fore200e_vcc* fore200e_vcc; - int i, pdu_len = 0; -#ifdef FORE200E_52BYTE_AAL0_SDU - u32 cell_header = 0; -#endif - - ASSERT(vcc); - - fore200e_vcc = FORE200E_VCC(vcc); - ASSERT(fore200e_vcc); - -#ifdef FORE200E_52BYTE_AAL0_SDU - if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { - - cell_header = (rpd->atm_header.gfc << ATM_HDR_GFC_SHIFT) | - (rpd->atm_header.vpi << ATM_HDR_VPI_SHIFT) | - (rpd->atm_header.vci << ATM_HDR_VCI_SHIFT) | - (rpd->atm_header.plt << ATM_HDR_PTI_SHIFT) | - rpd->atm_header.clp; - pdu_len = 4; - } -#endif - - /* compute total PDU length */ - for (i = 0; i < rpd->nseg; i++) - pdu_len += rpd->rsd[ i ].length; - - skb = alloc_skb(pdu_len, GFP_ATOMIC); - if (skb == NULL) { - DPRINTK(2, "unable to alloc new skb, rx PDU length = %d\n", pdu_len); - - atomic_inc(&vcc->stats->rx_drop); - return -ENOMEM; - } - - __net_timestamp(skb); - -#ifdef FORE200E_52BYTE_AAL0_SDU - if (cell_header) { - *((u32*)skb_put(skb, 4)) = cell_header; - } -#endif - - /* reassemble segments */ - for (i = 0; i < rpd->nseg; i++) { - - /* rebuild rx buffer address from rsd handle */ - buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); - - /* Make device DMA transfer visible to CPU. */ - dma_sync_single_for_cpu(fore200e->dev, buffer->data.dma_addr, - rpd->rsd[i].length, DMA_FROM_DEVICE); - - skb_put_data(skb, buffer->data.align_addr, rpd->rsd[i].length); - - /* Now let the device get at it again. */ - dma_sync_single_for_device(fore200e->dev, buffer->data.dma_addr, - rpd->rsd[i].length, DMA_FROM_DEVICE); - } - - DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); - - if (pdu_len < fore200e_vcc->rx_min_pdu) - fore200e_vcc->rx_min_pdu = pdu_len; - if (pdu_len > fore200e_vcc->rx_max_pdu) - fore200e_vcc->rx_max_pdu = pdu_len; - fore200e_vcc->rx_pdu++; - - /* push PDU */ - if (atm_charge(vcc, skb->truesize) == 0) { - - DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", - vcc->itf, vcc->vpi, vcc->vci); - - dev_kfree_skb_any(skb); - - atomic_inc(&vcc->stats->rx_drop); - return -ENOMEM; - } - - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - - return 0; -} - - -static void -fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) -{ - struct host_bsq* bsq; - struct buffer* buffer; - int i; - - for (i = 0; i < rpd->nseg; i++) { - - /* rebuild rx buffer address from rsd handle */ - buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); - - bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ]; - -#ifdef FORE200E_BSQ_DEBUG - bsq_audit(2, bsq, buffer->scheme, buffer->magn); - - if (buffer->supplied == 0) - printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n", - buffer->scheme, buffer->magn, buffer->index); - buffer->supplied = 0; -#endif - - /* re-insert the buffer into the free buffer list */ - buffer->next = bsq->freebuf; - bsq->freebuf = buffer; - - /* then increment the number of free rx buffers */ - bsq->freebuf_count++; - } -} - - -static void -fore200e_rx_irq(struct fore200e* fore200e) -{ - struct host_rxq* rxq = &fore200e->host_rxq; - struct host_rxq_entry* entry; - struct atm_vcc* vcc; - struct fore200e_vc_map* vc_map; - - for (;;) { - - entry = &rxq->host_entry[ rxq->head ]; - - /* no more received PDUs */ - if ((*entry->status & STATUS_COMPLETE) == 0) - break; - - vc_map = FORE200E_VC_MAP(fore200e, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); - - if ((vc_map->vcc == NULL) || - (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) { - - DPRINTK(1, "no ready VC found for PDU received on %d.%d.%d\n", - fore200e->atm_dev->number, - entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); - } - else { - vcc = vc_map->vcc; - ASSERT(vcc); - - if ((*entry->status & STATUS_ERROR) == 0) { - - fore200e_push_rpd(fore200e, vcc, entry->rpd); - } - else { - DPRINTK(2, "damaged PDU on %d.%d.%d\n", - fore200e->atm_dev->number, - entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); - atomic_inc(&vcc->stats->rx_err); - } - } - - FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); - - fore200e_collect_rpd(fore200e, entry->rpd); - - /* rewrite the rpd address to ack the received PDU */ - fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); - *entry->status = STATUS_FREE; - - fore200e_supply(fore200e); - } -} - - -#ifndef FORE200E_USE_TASKLET -static void -fore200e_irq(struct fore200e* fore200e) -{ - unsigned long flags; - - spin_lock_irqsave(&fore200e->q_lock, flags); - fore200e_rx_irq(fore200e); - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - spin_lock_irqsave(&fore200e->q_lock, flags); - fore200e_tx_irq(fore200e); - spin_unlock_irqrestore(&fore200e->q_lock, flags); -} -#endif - - -static irqreturn_t -fore200e_interrupt(int irq, void* dev) -{ - struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev); - - if (fore200e->bus->irq_check(fore200e) == 0) { - - DPRINTK(3, "interrupt NOT triggered by device %d\n", fore200e->atm_dev->number); - return IRQ_NONE; - } - DPRINTK(3, "interrupt triggered by device %d\n", fore200e->atm_dev->number); - -#ifdef FORE200E_USE_TASKLET - tasklet_schedule(&fore200e->tx_tasklet); - tasklet_schedule(&fore200e->rx_tasklet); -#else - fore200e_irq(fore200e); -#endif - - fore200e->bus->irq_ack(fore200e); - return IRQ_HANDLED; -} - - -#ifdef FORE200E_USE_TASKLET -static void -fore200e_tx_tasklet(unsigned long data) -{ - struct fore200e* fore200e = (struct fore200e*) data; - unsigned long flags; - - DPRINTK(3, "tx tasklet scheduled for device %d\n", fore200e->atm_dev->number); - - spin_lock_irqsave(&fore200e->q_lock, flags); - fore200e_tx_irq(fore200e); - spin_unlock_irqrestore(&fore200e->q_lock, flags); -} - - -static void -fore200e_rx_tasklet(unsigned long data) -{ - struct fore200e* fore200e = (struct fore200e*) data; - unsigned long flags; - - DPRINTK(3, "rx tasklet scheduled for device %d\n", fore200e->atm_dev->number); - - spin_lock_irqsave(&fore200e->q_lock, flags); - fore200e_rx_irq((struct fore200e*) data); - spin_unlock_irqrestore(&fore200e->q_lock, flags); -} -#endif - - -static int -fore200e_select_scheme(struct atm_vcc* vcc) -{ - /* fairly balance the VCs over (identical) buffer schemes */ - int scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO; - - DPRINTK(1, "VC %d.%d.%d uses buffer scheme %d\n", - vcc->itf, vcc->vpi, vcc->vci, scheme); - - return scheme; -} - - -static int -fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; - struct activate_opcode activ_opcode; - struct deactivate_opcode deactiv_opcode; - struct vpvc vpvc; - int ok; - enum fore200e_aal aal = fore200e_atm2fore_aal(vcc->qos.aal); - - FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); - - if (activate) { - FORE200E_VCC(vcc)->scheme = fore200e_select_scheme(vcc); - - activ_opcode.opcode = OPCODE_ACTIVATE_VCIN; - activ_opcode.aal = aal; - activ_opcode.scheme = FORE200E_VCC(vcc)->scheme; - activ_opcode.pad = 0; - } - else { - deactiv_opcode.opcode = OPCODE_DEACTIVATE_VCIN; - deactiv_opcode.pad = 0; - } - - vpvc.vci = vcc->vci; - vpvc.vpi = vcc->vpi; - - *entry->status = STATUS_PENDING; - - if (activate) { - -#ifdef FORE200E_52BYTE_AAL0_SDU - mtu = 48; -#endif - /* the MTU is not used by the cp, except in the case of AAL0 */ - fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); - fore200e->bus->write(*(u32*)&vpvc, (u32 __iomem *)&entry->cp_entry->cmd.activate_block.vpvc); - fore200e->bus->write(*(u32*)&activ_opcode, (u32 __iomem *)&entry->cp_entry->cmd.activate_block.opcode); - } - else { - fore200e->bus->write(*(u32*)&vpvc, (u32 __iomem *)&entry->cp_entry->cmd.deactivate_block.vpvc); - fore200e->bus->write(*(u32*)&deactiv_opcode, (u32 __iomem *)&entry->cp_entry->cmd.deactivate_block.opcode); - } - - ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); - - *entry->status = STATUS_FREE; - - if (ok == 0) { - printk(FORE200E "unable to %s VC %d.%d.%d\n", - activate ? "open" : "close", vcc->itf, vcc->vpi, vcc->vci); - return -EIO; - } - - DPRINTK(1, "VC %d.%d.%d %sed\n", vcc->itf, vcc->vpi, vcc->vci, - activate ? "open" : "clos"); - - return 0; -} - - -#define FORE200E_MAX_BACK2BACK_CELLS 255 /* XXX depends on CDVT */ - -static void -fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) -{ - if (qos->txtp.max_pcr < ATM_OC3_PCR) { - - /* compute the data cells to idle cells ratio from the tx PCR */ - rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; - rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; - } - else { - /* disable rate control */ - rate->data_cells = rate->idle_cells = 0; - } -} - - -static int -fore200e_open(struct atm_vcc *vcc) -{ - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); - struct fore200e_vcc* fore200e_vcc; - struct fore200e_vc_map* vc_map; - unsigned long flags; - int vci = vcc->vci; - short vpi = vcc->vpi; - - ASSERT((vpi >= 0) && (vpi < 1<= 0) && (vci < 1<q_lock, flags); - - vc_map = FORE200E_VC_MAP(fore200e, vpi, vci); - if (vc_map->vcc) { - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - printk(FORE200E "VC %d.%d.%d already in use\n", - fore200e->atm_dev->number, vpi, vci); - - return -EINVAL; - } - - vc_map->vcc = vcc; - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - fore200e_vcc = kzalloc_obj(struct fore200e_vcc, GFP_ATOMIC); - if (fore200e_vcc == NULL) { - vc_map->vcc = NULL; - return -ENOMEM; - } - - DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " - "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", - vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), - fore200e_traffic_class[ vcc->qos.txtp.traffic_class ], - vcc->qos.txtp.min_pcr, vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_cdv, vcc->qos.txtp.max_sdu, - fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], - vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); - - /* pseudo-CBR bandwidth requested? */ - if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { - - mutex_lock(&fore200e->rate_mtx); - if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { - mutex_unlock(&fore200e->rate_mtx); - - kfree(fore200e_vcc); - vc_map->vcc = NULL; - return -EAGAIN; - } - - /* reserve bandwidth */ - fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); - } - - vcc->itf = vcc->dev->number; - - set_bit(ATM_VF_PARTIAL,&vcc->flags); - set_bit(ATM_VF_ADDR, &vcc->flags); - - vcc->dev_data = fore200e_vcc; - - if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { - - vc_map->vcc = NULL; - - clear_bit(ATM_VF_ADDR, &vcc->flags); - clear_bit(ATM_VF_PARTIAL,&vcc->flags); - - vcc->dev_data = NULL; - - mutex_lock(&fore200e->rate_mtx); - fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); - - kfree(fore200e_vcc); - return -EINVAL; - } - - /* compute rate control parameters */ - if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { - - fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); - set_bit(ATM_VF_HASQOS, &vcc->flags); - - DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", - vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), - vcc->qos.txtp.max_pcr, vcc->qos.rxtp.max_pcr, - fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); - } - - fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = MAX_PDU_SIZE + 1; - fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; - fore200e_vcc->tx_pdu = fore200e_vcc->rx_pdu = 0; - - /* new incarnation of the vcc */ - vc_map->incarn = ++fore200e->incarn_count; - - /* VC unusable before this flag is set */ - set_bit(ATM_VF_READY, &vcc->flags); - - return 0; -} - - -static void -fore200e_close(struct atm_vcc* vcc) -{ - struct fore200e_vcc* fore200e_vcc; - struct fore200e* fore200e; - struct fore200e_vc_map* vc_map; - unsigned long flags; - - ASSERT(vcc); - fore200e = FORE200E_DEV(vcc->dev); - - ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<vci >= 0) && (vcc->vci < 1<itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); - - clear_bit(ATM_VF_READY, &vcc->flags); - - fore200e_activate_vcin(fore200e, 0, vcc, 0); - - spin_lock_irqsave(&fore200e->q_lock, flags); - - vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci); - - /* the vc is no longer considered as "in use" by fore200e_open() */ - vc_map->vcc = NULL; - - vcc->itf = vcc->vci = vcc->vpi = 0; - - fore200e_vcc = FORE200E_VCC(vcc); - vcc->dev_data = NULL; - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - /* release reserved bandwidth, if any */ - if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { - - mutex_lock(&fore200e->rate_mtx); - fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - mutex_unlock(&fore200e->rate_mtx); - - clear_bit(ATM_VF_HASQOS, &vcc->flags); - } - - clear_bit(ATM_VF_ADDR, &vcc->flags); - clear_bit(ATM_VF_PARTIAL,&vcc->flags); - - ASSERT(fore200e_vcc); - kfree(fore200e_vcc); -} - - -static int -fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct fore200e* fore200e; - struct fore200e_vcc* fore200e_vcc; - struct fore200e_vc_map* vc_map; - struct host_txq* txq; - struct host_txq_entry* entry; - struct tpd* tpd; - struct tpd_haddr tpd_haddr; - int retry = CONFIG_ATM_FORE200E_TX_RETRY; - int tx_copy = 0; - int tx_len = skb->len; - u32* cell_header = NULL; - unsigned char* skb_data; - int skb_len; - unsigned char* data; - unsigned long flags; - - if (!vcc) - return -EINVAL; - - fore200e = FORE200E_DEV(vcc->dev); - fore200e_vcc = FORE200E_VCC(vcc); - - if (!fore200e) - return -EINVAL; - - txq = &fore200e->host_txq; - if (!fore200e_vcc) - return -EINVAL; - - if (!test_bit(ATM_VF_READY, &vcc->flags)) { - DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi); - dev_kfree_skb_any(skb); - return -EINVAL; - } - -#ifdef FORE200E_52BYTE_AAL0_SDU - if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { - cell_header = (u32*) skb->data; - skb_data = skb->data + 4; /* skip 4-byte cell header */ - skb_len = tx_len = skb->len - 4; - - DPRINTK(3, "user-supplied cell header = 0x%08x\n", *cell_header); - } - else -#endif - { - skb_data = skb->data; - skb_len = skb->len; - } - - if (((unsigned long)skb_data) & 0x3) { - - DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name); - tx_copy = 1; - tx_len = skb_len; - } - - if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) { - - /* this simply NUKES the PCA board */ - DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name); - tx_copy = 1; - tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD; - } - - if (tx_copy) { - data = kmalloc(tx_len, GFP_ATOMIC); - if (data == NULL) { - if (vcc->pop) { - vcc->pop(vcc, skb); - } - else { - dev_kfree_skb_any(skb); - } - return -ENOMEM; - } - - memcpy(data, skb_data, skb_len); - if (skb_len < tx_len) - memset(data + skb_len, 0x00, tx_len - skb_len); - } - else { - data = skb_data; - } - - vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci); - ASSERT(vc_map->vcc == vcc); - - retry_here: - - spin_lock_irqsave(&fore200e->q_lock, flags); - - entry = &txq->host_entry[ txq->head ]; - - if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) { - - /* try to free completed tx queue entries */ - fore200e_tx_irq(fore200e); - - if (*entry->status != STATUS_FREE) { - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - /* retry once again? */ - if (--retry > 0) { - udelay(50); - goto retry_here; - } - - atomic_inc(&vcc->stats->tx_err); - - fore200e->tx_sat++; - DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", - fore200e->name, fore200e->cp_queues->heartbeat); - if (vcc->pop) { - vcc->pop(vcc, skb); - } - else { - dev_kfree_skb_any(skb); - } - - if (tx_copy) - kfree(data); - - return -ENOBUFS; - } - } - - entry->incarn = vc_map->incarn; - entry->vc_map = vc_map; - entry->skb = skb; - entry->data = tx_copy ? data : NULL; - - tpd = entry->tpd; - tpd->tsd[ 0 ].buffer = dma_map_single(fore200e->dev, data, tx_len, - DMA_TO_DEVICE); - if (dma_mapping_error(fore200e->dev, tpd->tsd[0].buffer)) { - if (tx_copy) - kfree(data); - spin_unlock_irqrestore(&fore200e->q_lock, flags); - return -ENOMEM; - } - tpd->tsd[ 0 ].length = tx_len; - - FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); - txq->txing++; - - /* The dma_map call above implies a dma_sync so the device can use it, - * thus no explicit dma_sync call is necessary here. - */ - - DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", - vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), - tpd->tsd[0].length, skb_len); - - if (skb_len < fore200e_vcc->tx_min_pdu) - fore200e_vcc->tx_min_pdu = skb_len; - if (skb_len > fore200e_vcc->tx_max_pdu) - fore200e_vcc->tx_max_pdu = skb_len; - fore200e_vcc->tx_pdu++; - - /* set tx rate control information */ - tpd->rate.data_cells = fore200e_vcc->rate.data_cells; - tpd->rate.idle_cells = fore200e_vcc->rate.idle_cells; - - if (cell_header) { - tpd->atm_header.clp = (*cell_header & ATM_HDR_CLP); - tpd->atm_header.plt = (*cell_header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; - tpd->atm_header.vci = (*cell_header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; - tpd->atm_header.vpi = (*cell_header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; - tpd->atm_header.gfc = (*cell_header & ATM_HDR_GFC_MASK) >> ATM_HDR_GFC_SHIFT; - } - else { - /* set the ATM header, common to all cells conveying the PDU */ - tpd->atm_header.clp = 0; - tpd->atm_header.plt = 0; - tpd->atm_header.vci = vcc->vci; - tpd->atm_header.vpi = vcc->vpi; - tpd->atm_header.gfc = 0; - } - - tpd->spec.length = tx_len; - tpd->spec.nseg = 1; - tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); - tpd->spec.intr = 1; - - tpd_haddr.size = sizeof(struct tpd) / (1<tpd_dma >> TPD_HADDR_SHIFT; /* shift the address, as we are in a bitfield */ - - *entry->status = STATUS_PENDING; - fore200e->bus->write(*(u32*)&tpd_haddr, (u32 __iomem *)&entry->cp_entry->tpd_haddr); - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - - return 0; -} - - -static int -fore200e_getstats(struct fore200e* fore200e) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; - struct stats_opcode opcode; - int ok; - u32 stats_dma_addr; - - if (fore200e->stats == NULL) { - fore200e->stats = kzalloc_obj(struct stats); - if (fore200e->stats == NULL) - return -ENOMEM; - } - - stats_dma_addr = dma_map_single(fore200e->dev, fore200e->stats, - sizeof(struct stats), DMA_FROM_DEVICE); - if (dma_mapping_error(fore200e->dev, stats_dma_addr)) - return -ENOMEM; - - FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); - - opcode.opcode = OPCODE_GET_STATS; - opcode.pad = 0; - - fore200e->bus->write(stats_dma_addr, &entry->cp_entry->cmd.stats_block.stats_haddr); - - *entry->status = STATUS_PENDING; - - fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.stats_block.opcode); - - ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); - - *entry->status = STATUS_FREE; - - dma_unmap_single(fore200e->dev, stats_dma_addr, sizeof(struct stats), DMA_FROM_DEVICE); - - if (ok == 0) { - printk(FORE200E "unable to get statistics from device %s\n", fore200e->name); - return -EIO; - } - - return 0; -} - -#if 0 /* currently unused */ -static int -fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; - struct oc3_opcode opcode; - int ok; - u32 oc3_regs_dma_addr; - - oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), DMA_FROM_DEVICE); - - FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); - - opcode.opcode = OPCODE_GET_OC3; - opcode.reg = 0; - opcode.value = 0; - opcode.mask = 0; - - fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr); - - *entry->status = STATUS_PENDING; - - fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode); - - ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); - - *entry->status = STATUS_FREE; - - fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), DMA_FROM_DEVICE); - - if (ok == 0) { - printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name); - return -EIO; - } - - return 0; -} -#endif - - -static int -fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ]; - struct oc3_opcode opcode; - int ok; - - DPRINTK(2, "set OC-3 reg = 0x%02x, value = 0x%02x, mask = 0x%02x\n", reg, value, mask); - - FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); - - opcode.opcode = OPCODE_SET_OC3; - opcode.reg = reg; - opcode.value = value; - opcode.mask = mask; - - fore200e->bus->write(0, &entry->cp_entry->cmd.oc3_block.regs_haddr); - - *entry->status = STATUS_PENDING; - - fore200e->bus->write(*(u32*)&opcode, (u32 __iomem *)&entry->cp_entry->cmd.oc3_block.opcode); - - ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400); - - *entry->status = STATUS_FREE; - - if (ok == 0) { - printk(FORE200E "unable to set OC-3 reg 0x%02x of device %s\n", reg, fore200e->name); - return -EIO; - } - - return 0; -} - - -static int -fore200e_setloop(struct fore200e* fore200e, int loop_mode) -{ - u32 mct_value, mct_mask; - int error; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch (loop_mode) { - - case ATM_LM_NONE: - mct_value = 0; - mct_mask = SUNI_MCT_DLE | SUNI_MCT_LLE; - break; - - case ATM_LM_LOC_PHY: - mct_value = mct_mask = SUNI_MCT_DLE; - break; - - case ATM_LM_RMT_PHY: - mct_value = mct_mask = SUNI_MCT_LLE; - break; - - default: - return -EINVAL; - } - - error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); - if (error == 0) - fore200e->loop_mode = loop_mode; - - return error; -} - - -static int -fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg) -{ - struct sonet_stats tmp; - - if (fore200e_getstats(fore200e) < 0) - return -EIO; - - tmp.section_bip = be32_to_cpu(fore200e->stats->oc3.section_bip8_errors); - tmp.line_bip = be32_to_cpu(fore200e->stats->oc3.line_bip24_errors); - tmp.path_bip = be32_to_cpu(fore200e->stats->oc3.path_bip8_errors); - tmp.line_febe = be32_to_cpu(fore200e->stats->oc3.line_febe_errors); - tmp.path_febe = be32_to_cpu(fore200e->stats->oc3.path_febe_errors); - tmp.corr_hcs = be32_to_cpu(fore200e->stats->oc3.corr_hcs_errors); - tmp.uncorr_hcs = be32_to_cpu(fore200e->stats->oc3.ucorr_hcs_errors); - tmp.tx_cells = be32_to_cpu(fore200e->stats->aal0.cells_transmitted) + - be32_to_cpu(fore200e->stats->aal34.cells_transmitted) + - be32_to_cpu(fore200e->stats->aal5.cells_transmitted); - tmp.rx_cells = be32_to_cpu(fore200e->stats->aal0.cells_received) + - be32_to_cpu(fore200e->stats->aal34.cells_received) + - be32_to_cpu(fore200e->stats->aal5.cells_received); - - if (arg) - return copy_to_user(arg, &tmp, sizeof(struct sonet_stats)) ? -EFAULT : 0; - - return 0; -} - - -static int -fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void __user * arg) -{ - struct fore200e* fore200e = FORE200E_DEV(dev); - - DPRINTK(2, "ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg); - - switch (cmd) { - - case SONET_GETSTAT: - return fore200e_fetch_stats(fore200e, (struct sonet_stats __user *)arg); - - case SONET_GETDIAG: - return put_user(0, (int __user *)arg) ? -EFAULT : 0; - - case ATM_SETLOOP: - return fore200e_setloop(fore200e, (int)(unsigned long)arg); - - case ATM_GETLOOP: - return put_user(fore200e->loop_mode, (int __user *)arg) ? -EFAULT : 0; - - case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, (int __user *)arg) ? -EFAULT : 0; - } - - return -ENOSYS; /* not implemented */ -} - - -static int -fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) -{ - struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); - struct fore200e* fore200e = FORE200E_DEV(vcc->dev); - - if (!test_bit(ATM_VF_READY, &vcc->flags)) { - DPRINTK(1, "VC %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi); - return -EINVAL; - } - - DPRINTK(2, "change_qos %d.%d.%d, " - "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " - "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" - "available_cell_rate = %u", - vcc->itf, vcc->vpi, vcc->vci, - fore200e_traffic_class[ qos->txtp.traffic_class ], - qos->txtp.min_pcr, qos->txtp.max_pcr, qos->txtp.max_cdv, qos->txtp.max_sdu, - fore200e_traffic_class[ qos->rxtp.traffic_class ], - qos->rxtp.min_pcr, qos->rxtp.max_pcr, qos->rxtp.max_cdv, qos->rxtp.max_sdu, - flags, fore200e->available_cell_rate); - - if ((qos->txtp.traffic_class == ATM_CBR) && (qos->txtp.max_pcr > 0)) { - - mutex_lock(&fore200e->rate_mtx); - if (fore200e->available_cell_rate + vcc->qos.txtp.max_pcr < qos->txtp.max_pcr) { - mutex_unlock(&fore200e->rate_mtx); - return -EAGAIN; - } - - fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; - fore200e->available_cell_rate -= qos->txtp.max_pcr; - - mutex_unlock(&fore200e->rate_mtx); - - memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); - - /* update rate control parameters */ - fore200e_rate_ctrl(qos, &fore200e_vcc->rate); - - set_bit(ATM_VF_HASQOS, &vcc->flags); - - return 0; - } - - return -EINVAL; -} - - -static int fore200e_irq_request(struct fore200e *fore200e) -{ - if (request_irq(fore200e->irq, fore200e_interrupt, IRQF_SHARED, fore200e->name, fore200e->atm_dev) < 0) { - - printk(FORE200E "unable to reserve IRQ %s for device %s\n", - fore200e_irq_itoa(fore200e->irq), fore200e->name); - return -EBUSY; - } - - printk(FORE200E "IRQ %s reserved for device %s\n", - fore200e_irq_itoa(fore200e->irq), fore200e->name); - -#ifdef FORE200E_USE_TASKLET - tasklet_init(&fore200e->tx_tasklet, fore200e_tx_tasklet, (unsigned long)fore200e); - tasklet_init(&fore200e->rx_tasklet, fore200e_rx_tasklet, (unsigned long)fore200e); -#endif - - fore200e->state = FORE200E_STATE_IRQ; - return 0; -} - - -static int fore200e_get_esi(struct fore200e *fore200e) -{ - struct prom_data* prom = kzalloc_obj(struct prom_data); - int ok, i; - - if (!prom) - return -ENOMEM; - - ok = fore200e->bus->prom_read(fore200e, prom); - if (ok < 0) { - kfree(prom); - return -EBUSY; - } - - printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %pM\n", - fore200e->name, - (prom->hw_revision & 0xFF) + '@', /* probably meaningless with SBA boards */ - prom->serial_number & 0xFFFF, &prom->mac_addr[2]); - - for (i = 0; i < ESI_LEN; i++) { - fore200e->esi[ i ] = fore200e->atm_dev->esi[ i ] = prom->mac_addr[ i + 2 ]; - } - - kfree(prom); - - return 0; -} - - -static int fore200e_alloc_rx_buf(struct fore200e *fore200e) -{ - int scheme, magn, nbr, size, i; - - struct host_bsq* bsq; - struct buffer* buffer; - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { - - bsq = &fore200e->host_bsq[ scheme ][ magn ]; - - nbr = fore200e_rx_buf_nbr[ scheme ][ magn ]; - size = fore200e_rx_buf_size[ scheme ][ magn ]; - - DPRINTK(2, "rx buffers %d / %d are being allocated\n", scheme, magn); - - /* allocate the array of receive buffers */ - buffer = bsq->buffer = kzalloc_objs(struct buffer, nbr); - - if (buffer == NULL) - return -ENOMEM; - - bsq->freebuf = NULL; - - for (i = 0; i < nbr; i++) { - - buffer[ i ].scheme = scheme; - buffer[ i ].magn = magn; -#ifdef FORE200E_BSQ_DEBUG - buffer[ i ].index = i; - buffer[ i ].supplied = 0; -#endif - - /* allocate the receive buffer body */ - if (fore200e_chunk_alloc(fore200e, - &buffer[ i ].data, size, fore200e->bus->buffer_alignment, - DMA_FROM_DEVICE) < 0) { - - while (i > 0) - fore200e_chunk_free(fore200e, &buffer[ --i ].data); - kfree(buffer); - - return -ENOMEM; - } - - /* insert the buffer into the free buffer list */ - buffer[ i ].next = bsq->freebuf; - bsq->freebuf = &buffer[ i ]; - } - /* all the buffers are free, initially */ - bsq->freebuf_count = nbr; - -#ifdef FORE200E_BSQ_DEBUG - bsq_audit(3, bsq, scheme, magn); -#endif - } - } - - fore200e->state = FORE200E_STATE_ALLOC_BUF; - return 0; -} - - -static int fore200e_init_bs_queue(struct fore200e *fore200e) -{ - int scheme, magn, i; - - struct host_bsq* bsq; - struct cp_bsq_entry __iomem * cp_entry; - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) { - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) { - - DPRINTK(2, "buffer supply queue %d / %d is being initialized\n", scheme, magn); - - bsq = &fore200e->host_bsq[ scheme ][ magn ]; - - /* allocate and align the array of status words */ - if (fore200e_dma_chunk_alloc(fore200e, - &bsq->status, - sizeof(enum status), - QUEUE_SIZE_BS, - fore200e->bus->status_alignment) < 0) { - return -ENOMEM; - } - - /* allocate and align the array of receive buffer descriptors */ - if (fore200e_dma_chunk_alloc(fore200e, - &bsq->rbd_block, - sizeof(struct rbd_block), - QUEUE_SIZE_BS, - fore200e->bus->descr_alignment) < 0) { - - fore200e_dma_chunk_free(fore200e, &bsq->status); - return -ENOMEM; - } - - /* get the base address of the cp resident buffer supply queue entries */ - cp_entry = fore200e->virt_base + - fore200e->bus->read(&fore200e->cp_queues->cp_bsq[ scheme ][ magn ]); - - /* fill the host resident and cp resident buffer supply queue entries */ - for (i = 0; i < QUEUE_SIZE_BS; i++) { - - bsq->host_entry[ i ].status = - FORE200E_INDEX(bsq->status.align_addr, enum status, i); - bsq->host_entry[ i ].rbd_block = - FORE200E_INDEX(bsq->rbd_block.align_addr, struct rbd_block, i); - bsq->host_entry[ i ].rbd_block_dma = - FORE200E_DMA_INDEX(bsq->rbd_block.dma_addr, struct rbd_block, i); - bsq->host_entry[ i ].cp_entry = &cp_entry[ i ]; - - *bsq->host_entry[ i ].status = STATUS_FREE; - - fore200e->bus->write(FORE200E_DMA_INDEX(bsq->status.dma_addr, enum status, i), - &cp_entry[ i ].status_haddr); - } - } - } - - fore200e->state = FORE200E_STATE_INIT_BSQ; - return 0; -} - - -static int fore200e_init_rx_queue(struct fore200e *fore200e) -{ - struct host_rxq* rxq = &fore200e->host_rxq; - struct cp_rxq_entry __iomem * cp_entry; - int i; - - DPRINTK(2, "receive queue is being initialized\n"); - - /* allocate and align the array of status words */ - if (fore200e_dma_chunk_alloc(fore200e, - &rxq->status, - sizeof(enum status), - QUEUE_SIZE_RX, - fore200e->bus->status_alignment) < 0) { - return -ENOMEM; - } - - /* allocate and align the array of receive PDU descriptors */ - if (fore200e_dma_chunk_alloc(fore200e, - &rxq->rpd, - sizeof(struct rpd), - QUEUE_SIZE_RX, - fore200e->bus->descr_alignment) < 0) { - - fore200e_dma_chunk_free(fore200e, &rxq->status); - return -ENOMEM; - } - - /* get the base address of the cp resident rx queue entries */ - cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_rxq); - - /* fill the host resident and cp resident rx entries */ - for (i=0; i < QUEUE_SIZE_RX; i++) { - - rxq->host_entry[ i ].status = - FORE200E_INDEX(rxq->status.align_addr, enum status, i); - rxq->host_entry[ i ].rpd = - FORE200E_INDEX(rxq->rpd.align_addr, struct rpd, i); - rxq->host_entry[ i ].rpd_dma = - FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i); - rxq->host_entry[ i ].cp_entry = &cp_entry[ i ]; - - *rxq->host_entry[ i ].status = STATUS_FREE; - - fore200e->bus->write(FORE200E_DMA_INDEX(rxq->status.dma_addr, enum status, i), - &cp_entry[ i ].status_haddr); - - fore200e->bus->write(FORE200E_DMA_INDEX(rxq->rpd.dma_addr, struct rpd, i), - &cp_entry[ i ].rpd_haddr); - } - - /* set the head entry of the queue */ - rxq->head = 0; - - fore200e->state = FORE200E_STATE_INIT_RXQ; - return 0; -} - - -static int fore200e_init_tx_queue(struct fore200e *fore200e) -{ - struct host_txq* txq = &fore200e->host_txq; - struct cp_txq_entry __iomem * cp_entry; - int i; - - DPRINTK(2, "transmit queue is being initialized\n"); - - /* allocate and align the array of status words */ - if (fore200e_dma_chunk_alloc(fore200e, - &txq->status, - sizeof(enum status), - QUEUE_SIZE_TX, - fore200e->bus->status_alignment) < 0) { - return -ENOMEM; - } - - /* allocate and align the array of transmit PDU descriptors */ - if (fore200e_dma_chunk_alloc(fore200e, - &txq->tpd, - sizeof(struct tpd), - QUEUE_SIZE_TX, - fore200e->bus->descr_alignment) < 0) { - - fore200e_dma_chunk_free(fore200e, &txq->status); - return -ENOMEM; - } - - /* get the base address of the cp resident tx queue entries */ - cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_txq); - - /* fill the host resident and cp resident tx entries */ - for (i=0; i < QUEUE_SIZE_TX; i++) { - - txq->host_entry[ i ].status = - FORE200E_INDEX(txq->status.align_addr, enum status, i); - txq->host_entry[ i ].tpd = - FORE200E_INDEX(txq->tpd.align_addr, struct tpd, i); - txq->host_entry[ i ].tpd_dma = - FORE200E_DMA_INDEX(txq->tpd.dma_addr, struct tpd, i); - txq->host_entry[ i ].cp_entry = &cp_entry[ i ]; - - *txq->host_entry[ i ].status = STATUS_FREE; - - fore200e->bus->write(FORE200E_DMA_INDEX(txq->status.dma_addr, enum status, i), - &cp_entry[ i ].status_haddr); - - /* although there is a one-to-one mapping of tx queue entries and tpds, - we do not write here the DMA (physical) base address of each tpd into - the related cp resident entry, because the cp relies on this write - operation to detect that a new pdu has been submitted for tx */ - } - - /* set the head and tail entries of the queue */ - txq->head = 0; - txq->tail = 0; - - fore200e->state = FORE200E_STATE_INIT_TXQ; - return 0; -} - - -static int fore200e_init_cmd_queue(struct fore200e *fore200e) -{ - struct host_cmdq* cmdq = &fore200e->host_cmdq; - struct cp_cmdq_entry __iomem * cp_entry; - int i; - - DPRINTK(2, "command queue is being initialized\n"); - - /* allocate and align the array of status words */ - if (fore200e_dma_chunk_alloc(fore200e, - &cmdq->status, - sizeof(enum status), - QUEUE_SIZE_CMD, - fore200e->bus->status_alignment) < 0) { - return -ENOMEM; - } - - /* get the base address of the cp resident cmd queue entries */ - cp_entry = fore200e->virt_base + fore200e->bus->read(&fore200e->cp_queues->cp_cmdq); - - /* fill the host resident and cp resident cmd entries */ - for (i=0; i < QUEUE_SIZE_CMD; i++) { - - cmdq->host_entry[ i ].status = - FORE200E_INDEX(cmdq->status.align_addr, enum status, i); - cmdq->host_entry[ i ].cp_entry = &cp_entry[ i ]; - - *cmdq->host_entry[ i ].status = STATUS_FREE; - - fore200e->bus->write(FORE200E_DMA_INDEX(cmdq->status.dma_addr, enum status, i), - &cp_entry[ i ].status_haddr); - } - - /* set the head entry of the queue */ - cmdq->head = 0; - - fore200e->state = FORE200E_STATE_INIT_CMDQ; - return 0; -} - - -static void fore200e_param_bs_queue(struct fore200e *fore200e, - enum buffer_scheme scheme, - enum buffer_magn magn, int queue_length, - int pool_size, int supply_blksize) -{ - struct bs_spec __iomem * bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; - - fore200e->bus->write(queue_length, &bs_spec->queue_length); - fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); - fore200e->bus->write(pool_size, &bs_spec->pool_size); - fore200e->bus->write(supply_blksize, &bs_spec->supply_blksize); -} - - -static int fore200e_initialize(struct fore200e *fore200e) -{ - struct cp_queues __iomem * cpq; - int ok, scheme, magn; - - DPRINTK(2, "device %s being initialized\n", fore200e->name); - - mutex_init(&fore200e->rate_mtx); - spin_lock_init(&fore200e->q_lock); - - cpq = fore200e->cp_queues = fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET; - - /* enable cp to host interrupts */ - fore200e->bus->write(1, &cpq->imask); - - if (fore200e->bus->irq_enable) - fore200e->bus->irq_enable(fore200e); - - fore200e->bus->write(NBR_CONNECT, &cpq->init.num_connect); - - fore200e->bus->write(QUEUE_SIZE_CMD, &cpq->init.cmd_queue_len); - fore200e->bus->write(QUEUE_SIZE_RX, &cpq->init.rx_queue_len); - fore200e->bus->write(QUEUE_SIZE_TX, &cpq->init.tx_queue_len); - - fore200e->bus->write(RSD_EXTENSION, &cpq->init.rsd_extension); - fore200e->bus->write(TSD_EXTENSION, &cpq->init.tsd_extension); - - for (scheme = 0; scheme < BUFFER_SCHEME_NBR; scheme++) - for (magn = 0; magn < BUFFER_MAGN_NBR; magn++) - fore200e_param_bs_queue(fore200e, scheme, magn, - QUEUE_SIZE_BS, - fore200e_rx_buf_nbr[ scheme ][ magn ], - RBD_BLK_SIZE); - - /* issue the initialize command */ - fore200e->bus->write(STATUS_PENDING, &cpq->init.status); - fore200e->bus->write(OPCODE_INITIALIZE, &cpq->init.opcode); - - ok = fore200e_io_poll(fore200e, &cpq->init.status, STATUS_COMPLETE, 3000); - if (ok == 0) { - printk(FORE200E "device %s initialization failed\n", fore200e->name); - return -ENODEV; - } - - printk(FORE200E "device %s initialized\n", fore200e->name); - - fore200e->state = FORE200E_STATE_INITIALIZE; - return 0; -} - - -static void fore200e_monitor_putc(struct fore200e *fore200e, char c) -{ - struct cp_monitor __iomem * monitor = fore200e->cp_monitor; - -#if 0 - printk("%c", c); -#endif - fore200e->bus->write(((u32) c) | FORE200E_CP_MONITOR_UART_AVAIL, &monitor->soft_uart.send); -} - - -static int fore200e_monitor_getc(struct fore200e *fore200e) -{ - struct cp_monitor __iomem * monitor = fore200e->cp_monitor; - unsigned long timeout = jiffies + msecs_to_jiffies(50); - int c; - - while (time_before(jiffies, timeout)) { - - c = (int) fore200e->bus->read(&monitor->soft_uart.recv); - - if (c & FORE200E_CP_MONITOR_UART_AVAIL) { - - fore200e->bus->write(FORE200E_CP_MONITOR_UART_FREE, &monitor->soft_uart.recv); -#if 0 - printk("%c", c & 0xFF); -#endif - return c & 0xFF; - } - } - - return -1; -} - - -static void fore200e_monitor_puts(struct fore200e *fore200e, char *str) -{ - while (*str) { - - /* the i960 monitor doesn't accept any new character if it has something to say */ - while (fore200e_monitor_getc(fore200e) >= 0); - - fore200e_monitor_putc(fore200e, *str++); - } - - while (fore200e_monitor_getc(fore200e) >= 0); -} - -#ifdef __LITTLE_ENDIAN -#define FW_EXT ".bin" -#else -#define FW_EXT "_ecd.bin2" -#endif - -static int fore200e_load_and_start_fw(struct fore200e *fore200e) -{ - const struct firmware *firmware; - const struct fw_header *fw_header; - const __le32 *fw_data; - u32 fw_size; - u32 __iomem *load_addr; - char buf[48]; - int err; - - sprintf(buf, "%s%s", fore200e->bus->proc_name, FW_EXT); - if ((err = request_firmware(&firmware, buf, fore200e->dev)) < 0) { - printk(FORE200E "problem loading firmware image %s\n", fore200e->bus->model_name); - return err; - } - - fw_data = (const __le32 *)firmware->data; - fw_size = firmware->size / sizeof(u32); - fw_header = (const struct fw_header *)firmware->data; - load_addr = fore200e->virt_base + le32_to_cpu(fw_header->load_offset); - - DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", - fore200e->name, load_addr, fw_size); - - if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { - printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); - goto release; - } - - for (; fw_size--; fw_data++, load_addr++) - fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); - - DPRINTK(2, "device %s firmware being started\n", fore200e->name); - -#if defined(__sparc_v9__) - /* reported to be required by SBA cards on some sparc64 hosts */ - fore200e_spin(100); -#endif - - sprintf(buf, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); - fore200e_monitor_puts(fore200e, buf); - - if (fore200e_io_poll(fore200e, &fore200e->cp_monitor->bstat, BSTAT_CP_RUNNING, 1000) == 0) { - printk(FORE200E "device %s firmware didn't start\n", fore200e->name); - goto release; - } - - printk(FORE200E "device %s firmware started\n", fore200e->name); - - fore200e->state = FORE200E_STATE_START_FW; - err = 0; - -release: - release_firmware(firmware); - return err; -} - - -static int fore200e_register(struct fore200e *fore200e, struct device *parent) -{ - struct atm_dev* atm_dev; - - DPRINTK(2, "device %s being registered\n", fore200e->name); - - atm_dev = atm_dev_register(fore200e->bus->proc_name, parent, &fore200e_ops, - -1, NULL); - if (atm_dev == NULL) { - printk(FORE200E "unable to register device %s\n", fore200e->name); - return -ENODEV; - } - - atm_dev->dev_data = fore200e; - fore200e->atm_dev = atm_dev; - - atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS; - atm_dev->ci_range.vci_bits = FORE200E_VCI_BITS; - - fore200e->available_cell_rate = ATM_OC3_PCR; - - fore200e->state = FORE200E_STATE_REGISTER; - return 0; -} - - -static int fore200e_init(struct fore200e *fore200e, struct device *parent) -{ - if (fore200e_register(fore200e, parent) < 0) - return -ENODEV; - - if (fore200e->bus->configure(fore200e) < 0) - return -ENODEV; - - if (fore200e->bus->map(fore200e) < 0) - return -ENODEV; - - if (fore200e_reset(fore200e, 1) < 0) - return -ENODEV; - - if (fore200e_load_and_start_fw(fore200e) < 0) - return -ENODEV; - - if (fore200e_initialize(fore200e) < 0) - return -ENODEV; - - if (fore200e_init_cmd_queue(fore200e) < 0) - return -ENOMEM; - - if (fore200e_init_tx_queue(fore200e) < 0) - return -ENOMEM; - - if (fore200e_init_rx_queue(fore200e) < 0) - return -ENOMEM; - - if (fore200e_init_bs_queue(fore200e) < 0) - return -ENOMEM; - - if (fore200e_alloc_rx_buf(fore200e) < 0) - return -ENOMEM; - - if (fore200e_get_esi(fore200e) < 0) - return -EIO; - - if (fore200e_irq_request(fore200e) < 0) - return -EBUSY; - - fore200e_supply(fore200e); - - /* all done, board initialization is now complete */ - fore200e->state = FORE200E_STATE_COMPLETE; - return 0; -} - -#ifdef CONFIG_SBUS -static int fore200e_sba_probe(struct platform_device *op) -{ - struct fore200e *fore200e; - static int index = 0; - int err; - - fore200e = kzalloc_obj(struct fore200e); - if (!fore200e) - return -ENOMEM; - - fore200e->bus = &fore200e_sbus_ops; - fore200e->dev = &op->dev; - fore200e->irq = op->archdata.irqs[0]; - fore200e->phys_base = op->resource[0].start; - - sprintf(fore200e->name, "SBA-200E-%d", index); - - err = fore200e_init(fore200e, &op->dev); - if (err < 0) { - fore200e_shutdown(fore200e); - kfree(fore200e); - return err; - } - - index++; - dev_set_drvdata(&op->dev, fore200e); - - return 0; -} - -static void fore200e_sba_remove(struct platform_device *op) -{ - struct fore200e *fore200e = dev_get_drvdata(&op->dev); - - fore200e_shutdown(fore200e); - kfree(fore200e); -} - -static const struct of_device_id fore200e_sba_match[] = { - { - .name = SBA200E_PROM_NAME, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, fore200e_sba_match); - -static struct platform_driver fore200e_sba_driver = { - .driver = { - .name = "fore_200e", - .of_match_table = fore200e_sba_match, - }, - .probe = fore200e_sba_probe, - .remove = fore200e_sba_remove, -}; -#endif - -#ifdef CONFIG_PCI -static int fore200e_pca_detect(struct pci_dev *pci_dev, - const struct pci_device_id *pci_ent) -{ - struct fore200e* fore200e; - int err = 0; - static int index = 0; - - if (pci_enable_device(pci_dev)) { - err = -EINVAL; - goto out; - } - - if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) { - err = -EINVAL; - goto out; - } - - fore200e = kzalloc_obj(struct fore200e); - if (fore200e == NULL) { - err = -ENOMEM; - goto out_disable; - } - - fore200e->bus = &fore200e_pci_ops; - fore200e->dev = &pci_dev->dev; - fore200e->irq = pci_dev->irq; - fore200e->phys_base = pci_resource_start(pci_dev, 0); - - sprintf(fore200e->name, "PCA-200E-%d", index - 1); - - pci_set_master(pci_dev); - - printk(FORE200E "device PCA-200E found at 0x%lx, IRQ %s\n", - fore200e->phys_base, fore200e_irq_itoa(fore200e->irq)); - - sprintf(fore200e->name, "PCA-200E-%d", index); - - err = fore200e_init(fore200e, &pci_dev->dev); - if (err < 0) { - fore200e_shutdown(fore200e); - goto out_free; - } - - ++index; - pci_set_drvdata(pci_dev, fore200e); - -out: - return err; - -out_free: - kfree(fore200e); -out_disable: - pci_disable_device(pci_dev); - goto out; -} - - -static void fore200e_pca_remove_one(struct pci_dev *pci_dev) -{ - struct fore200e *fore200e; - - fore200e = pci_get_drvdata(pci_dev); - - fore200e_shutdown(fore200e); - kfree(fore200e); - pci_disable_device(pci_dev); -} - - -static const struct pci_device_id fore200e_pca_tbl[] = { - { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_PCA200E, PCI_ANY_ID, PCI_ANY_ID }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, fore200e_pca_tbl); - -static struct pci_driver fore200e_pca_driver = { - .name = "fore_200e", - .probe = fore200e_pca_detect, - .remove = fore200e_pca_remove_one, - .id_table = fore200e_pca_tbl, -}; -#endif - -static int __init fore200e_module_init(void) -{ - int err = 0; - - printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); - -#ifdef CONFIG_SBUS - err = platform_driver_register(&fore200e_sba_driver); - if (err) - return err; -#endif - -#ifdef CONFIG_PCI - err = pci_register_driver(&fore200e_pca_driver); -#endif - -#ifdef CONFIG_SBUS - if (err) - platform_driver_unregister(&fore200e_sba_driver); -#endif - - return err; -} - -static void __exit fore200e_module_cleanup(void) -{ -#ifdef CONFIG_PCI - pci_unregister_driver(&fore200e_pca_driver); -#endif -#ifdef CONFIG_SBUS - platform_driver_unregister(&fore200e_sba_driver); -#endif -} - -static int -fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page) -{ - struct fore200e* fore200e = FORE200E_DEV(dev); - struct fore200e_vcc* fore200e_vcc; - struct atm_vcc* vcc; - int i, len, left = *pos; - unsigned long flags; - - if (!left--) { - - if (fore200e_getstats(fore200e) < 0) - return -EIO; - - len = sprintf(page,"\n" - " device:\n" - " internal name:\t\t%s\n", fore200e->name); - - /* print bus-specific information */ - if (fore200e->bus->proc_read) - len += fore200e->bus->proc_read(fore200e, page + len); - - len += sprintf(page + len, - " interrupt line:\t\t%s\n" - " physical base address:\t0x%p\n" - " virtual base address:\t0x%p\n" - " factory address (ESI):\t%pM\n" - " board serial number:\t\t%d\n\n", - fore200e_irq_itoa(fore200e->irq), - (void*)fore200e->phys_base, - fore200e->virt_base, - fore200e->esi, - fore200e->esi[4] * 256 + fore200e->esi[5]); - - return len; - } - - if (!left--) - return sprintf(page, - " free small bufs, scheme 1:\t%d\n" - " free large bufs, scheme 1:\t%d\n" - " free small bufs, scheme 2:\t%d\n" - " free large bufs, scheme 2:\t%d\n", - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count, - fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count, - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count, - fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count); - - if (!left--) { - u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); - - len = sprintf(page,"\n\n" - " cell processor:\n" - " heartbeat state:\t\t"); - - if (hb >> 16 != 0xDEAD) - len += sprintf(page + len, "0x%08x\n", hb); - else - len += sprintf(page + len, "*** FATAL ERROR %04x ***\n", hb & 0xFFFF); - - return len; - } - - if (!left--) { - static const char* media_name[] = { - "unshielded twisted pair", - "multimode optical fiber ST", - "multimode optical fiber SC", - "single-mode optical fiber ST", - "single-mode optical fiber SC", - "unknown" - }; - - static const char* oc3_mode[] = { - "normal operation", - "diagnostic loopback", - "line loopback", - "unknown" - }; - - u32 fw_release = fore200e->bus->read(&fore200e->cp_queues->fw_release); - u32 mon960_release = fore200e->bus->read(&fore200e->cp_queues->mon960_release); - u32 oc3_revision = fore200e->bus->read(&fore200e->cp_queues->oc3_revision); - u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); - u32 oc3_index; - - if (media_index > 4) - media_index = 5; - - switch (fore200e->loop_mode) { - case ATM_LM_NONE: oc3_index = 0; - break; - case ATM_LM_LOC_PHY: oc3_index = 1; - break; - case ATM_LM_RMT_PHY: oc3_index = 2; - break; - default: oc3_index = 3; - } - - return sprintf(page, - " firmware release:\t\t%d.%d.%d\n" - " monitor release:\t\t%d.%d\n" - " media type:\t\t\t%s\n" - " OC-3 revision:\t\t0x%x\n" - " OC-3 mode:\t\t\t%s", - fw_release >> 16, fw_release << 16 >> 24, fw_release << 24 >> 24, - mon960_release >> 16, mon960_release << 16 >> 16, - media_name[ media_index ], - oc3_revision, - oc3_mode[ oc3_index ]); - } - - if (!left--) { - struct cp_monitor __iomem * cp_monitor = fore200e->cp_monitor; - - return sprintf(page, - "\n\n" - " monitor:\n" - " version number:\t\t%d\n" - " boot status word:\t\t0x%08x\n", - fore200e->bus->read(&cp_monitor->mon_version), - fore200e->bus->read(&cp_monitor->bstat)); - } - - if (!left--) - return sprintf(page, - "\n" - " device statistics:\n" - " 4b5b:\n" - " crc_header_errors:\t\t%10u\n" - " framing_errors:\t\t%10u\n", - be32_to_cpu(fore200e->stats->phy.crc_header_errors), - be32_to_cpu(fore200e->stats->phy.framing_errors)); - - if (!left--) - return sprintf(page, "\n" - " OC-3:\n" - " section_bip8_errors:\t%10u\n" - " path_bip8_errors:\t\t%10u\n" - " line_bip24_errors:\t\t%10u\n" - " line_febe_errors:\t\t%10u\n" - " path_febe_errors:\t\t%10u\n" - " corr_hcs_errors:\t\t%10u\n" - " ucorr_hcs_errors:\t\t%10u\n", - be32_to_cpu(fore200e->stats->oc3.section_bip8_errors), - be32_to_cpu(fore200e->stats->oc3.path_bip8_errors), - be32_to_cpu(fore200e->stats->oc3.line_bip24_errors), - be32_to_cpu(fore200e->stats->oc3.line_febe_errors), - be32_to_cpu(fore200e->stats->oc3.path_febe_errors), - be32_to_cpu(fore200e->stats->oc3.corr_hcs_errors), - be32_to_cpu(fore200e->stats->oc3.ucorr_hcs_errors)); - - if (!left--) - return sprintf(page,"\n" - " ATM:\t\t\t\t cells\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " vpi out of range:\t\t%10u\n" - " vpi no conn:\t\t%10u\n" - " vci out of range:\t\t%10u\n" - " vci no conn:\t\t%10u\n", - be32_to_cpu(fore200e->stats->atm.cells_transmitted), - be32_to_cpu(fore200e->stats->atm.cells_received), - be32_to_cpu(fore200e->stats->atm.vpi_bad_range), - be32_to_cpu(fore200e->stats->atm.vpi_no_conn), - be32_to_cpu(fore200e->stats->atm.vci_bad_range), - be32_to_cpu(fore200e->stats->atm.vci_no_conn)); - - if (!left--) - return sprintf(page,"\n" - " AAL0:\t\t\t cells\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " dropped:\t\t\t%10u\n", - be32_to_cpu(fore200e->stats->aal0.cells_transmitted), - be32_to_cpu(fore200e->stats->aal0.cells_received), - be32_to_cpu(fore200e->stats->aal0.cells_dropped)); - - if (!left--) - return sprintf(page,"\n" - " AAL3/4:\n" - " SAR sublayer:\t\t cells\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " dropped:\t\t\t%10u\n" - " CRC errors:\t\t%10u\n" - " protocol errors:\t\t%10u\n\n" - " CS sublayer:\t\t PDUs\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " dropped:\t\t\t%10u\n" - " protocol errors:\t\t%10u\n", - be32_to_cpu(fore200e->stats->aal34.cells_transmitted), - be32_to_cpu(fore200e->stats->aal34.cells_received), - be32_to_cpu(fore200e->stats->aal34.cells_dropped), - be32_to_cpu(fore200e->stats->aal34.cells_crc_errors), - be32_to_cpu(fore200e->stats->aal34.cells_protocol_errors), - be32_to_cpu(fore200e->stats->aal34.cspdus_transmitted), - be32_to_cpu(fore200e->stats->aal34.cspdus_received), - be32_to_cpu(fore200e->stats->aal34.cspdus_dropped), - be32_to_cpu(fore200e->stats->aal34.cspdus_protocol_errors)); - - if (!left--) - return sprintf(page,"\n" - " AAL5:\n" - " SAR sublayer:\t\t cells\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " dropped:\t\t\t%10u\n" - " congestions:\t\t%10u\n\n" - " CS sublayer:\t\t PDUs\n" - " TX:\t\t\t%10u\n" - " RX:\t\t\t%10u\n" - " dropped:\t\t\t%10u\n" - " CRC errors:\t\t%10u\n" - " protocol errors:\t\t%10u\n", - be32_to_cpu(fore200e->stats->aal5.cells_transmitted), - be32_to_cpu(fore200e->stats->aal5.cells_received), - be32_to_cpu(fore200e->stats->aal5.cells_dropped), - be32_to_cpu(fore200e->stats->aal5.congestion_experienced), - be32_to_cpu(fore200e->stats->aal5.cspdus_transmitted), - be32_to_cpu(fore200e->stats->aal5.cspdus_received), - be32_to_cpu(fore200e->stats->aal5.cspdus_dropped), - be32_to_cpu(fore200e->stats->aal5.cspdus_crc_errors), - be32_to_cpu(fore200e->stats->aal5.cspdus_protocol_errors)); - - if (!left--) - return sprintf(page,"\n" - " AUX:\t\t allocation failures\n" - " small b1:\t\t\t%10u\n" - " large b1:\t\t\t%10u\n" - " small b2:\t\t\t%10u\n" - " large b2:\t\t\t%10u\n" - " RX PDUs:\t\t\t%10u\n" - " TX PDUs:\t\t\t%10lu\n", - be32_to_cpu(fore200e->stats->aux.small_b1_failed), - be32_to_cpu(fore200e->stats->aux.large_b1_failed), - be32_to_cpu(fore200e->stats->aux.small_b2_failed), - be32_to_cpu(fore200e->stats->aux.large_b2_failed), - be32_to_cpu(fore200e->stats->aux.rpd_alloc_failed), - fore200e->tx_sat); - - if (!left--) - return sprintf(page,"\n" - " receive carrier:\t\t\t%s\n", - fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); - - if (!left--) { - return sprintf(page,"\n" - " VCCs:\n address VPI VCI AAL " - "TX PDUs TX min/max size RX PDUs RX min/max size\n"); - } - - for (i = 0; i < NBR_CONNECT; i++) { - - vcc = fore200e->vc_map[i].vcc; - - if (vcc == NULL) - continue; - - spin_lock_irqsave(&fore200e->q_lock, flags); - - if (vcc && test_bit(ATM_VF_READY, &vcc->flags) && !left--) { - - fore200e_vcc = FORE200E_VCC(vcc); - ASSERT(fore200e_vcc); - - len = sprintf(page, - " %pK %03d %05d %1d %09lu %05d/%05d %09lu %05d/%05d\n", - vcc, - vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), - fore200e_vcc->tx_pdu, - fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, - fore200e_vcc->tx_max_pdu, - fore200e_vcc->rx_pdu, - fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, - fore200e_vcc->rx_max_pdu); - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - return len; - } - - spin_unlock_irqrestore(&fore200e->q_lock, flags); - } - - return 0; -} - -module_init(fore200e_module_init); -module_exit(fore200e_module_cleanup); - - -static const struct atmdev_ops fore200e_ops = { - .open = fore200e_open, - .close = fore200e_close, - .ioctl = fore200e_ioctl, - .send = fore200e_send, - .change_qos = fore200e_change_qos, - .proc_read = fore200e_proc_read, - .owner = THIS_MODULE -}; - -MODULE_LICENSE("GPL"); -#ifdef CONFIG_PCI -#ifdef __LITTLE_ENDIAN__ -MODULE_FIRMWARE("pca200e.bin"); -#else -MODULE_FIRMWARE("pca200e_ecd.bin2"); -#endif -#endif /* CONFIG_PCI */ -#ifdef CONFIG_SBUS -MODULE_FIRMWARE("sba200e_ecd.bin2"); -#endif diff --git a/drivers/atm/he.c b/drivers/atm/he.c deleted file mode 100644 index bb9cb00f9585..000000000000 --- a/drivers/atm/he.c +++ /dev/null @@ -1,2861 +0,0 @@ -/* - - he.c - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2001 Naval Research Laboratory - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -*/ - -/* - - he.c - - ForeRunnerHE ATM Adapter driver for ATM on Linux - Copyright (C) 1999-2001 Naval Research Laboratory - - Permission to use, copy, modify and distribute this software and its - documentation is hereby granted, provided that both the copyright - notice and this permission notice appear in all copies of the software, - derivative works or modified versions, and any portions thereof, and - that both notices appear in supporting documentation. - - NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND - DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER - RESULTING FROM THE USE OF THIS SOFTWARE. - - This driver was written using the "Programmer's Reference Manual for - ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98. - - AUTHORS: - chas williams - eric kinzie - - NOTES: - 4096 supported 'connections' - group 0 is used for all traffic - interrupt queue 0 is used for all interrupts - aal0 support (based on work from ulrich.u.muller@nokia.com) - - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#undef USE_SCATTERGATHER -#undef USE_CHECKSUM_HW /* still confused about this */ -/* #undef HE_DEBUG */ - -#include "he.h" -#include "suni.h" -#include - -#define hprintk(fmt,args...) printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number , ##args) - -#ifdef HE_DEBUG -#define HPRINTK(fmt,args...) printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args) -#else /* !HE_DEBUG */ -#define HPRINTK(fmt,args...) do { } while (0) -#endif /* HE_DEBUG */ - -/* declarations */ - -static int he_open(struct atm_vcc *vcc); -static void he_close(struct atm_vcc *vcc); -static int he_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg); -static irqreturn_t he_irq_handler(int irq, void *dev_id); -static void he_tasklet(unsigned long data); -static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page); -static int he_start(struct atm_dev *dev); -static void he_stop(struct he_dev *dev); -static void he_phy_put(struct atm_dev *, unsigned char, unsigned long); -static unsigned char he_phy_get(struct atm_dev *, unsigned long); - -static u8 read_prom_byte(struct he_dev *he_dev, int addr); - -/* globals */ - -static struct he_dev *he_devs; -static bool disable64; -static short nvpibits = -1; -static short nvcibits = -1; -static short rx_skb_reserve = 16; -static bool irq_coalesce = true; -static bool sdh; - -/* Read from EEPROM = 0000 0011b */ -static unsigned int readtab[] = { - CS_HIGH | CLK_HIGH, - CS_LOW | CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH, /* 1 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH /* 1 */ -}; - -/* Clock to read from/write to the EEPROM */ -static unsigned int clocktab[] = { - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW -}; - -static const struct atmdev_ops he_ops = -{ - .open = he_open, - .close = he_close, - .ioctl = he_ioctl, - .send = he_send, - .phy_put = he_phy_put, - .phy_get = he_phy_get, - .proc_read = he_proc_read, - .owner = THIS_MODULE -}; - -#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0) -#define he_readl(dev, reg) readl((dev)->membase + (reg)) - -/* section 2.12 connection memory access */ - -static __inline__ void -he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr, - unsigned flags) -{ - he_writel(he_dev, val, CON_DAT); - (void) he_readl(he_dev, CON_DAT); /* flush posted writes */ - he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL); - while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); -} - -#define he_writel_rcm(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_RCM) - -#define he_writel_tcm(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_TCM) - -#define he_writel_mbox(dev, val, reg) \ - he_writel_internal(dev, val, reg, CON_CTL_MBOX) - -static unsigned -he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) -{ - he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL); - while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); - return he_readl(he_dev, CON_DAT); -} - -#define he_readl_rcm(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_RCM) - -#define he_readl_tcm(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_TCM) - -#define he_readl_mbox(dev, reg) \ - he_readl_internal(dev, reg, CON_CTL_MBOX) - - -/* figure 2.2 connection id */ - -#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff) - -/* 2.5.1 per connection transmit state registers */ - -#define he_writel_tsr0(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0) -#define he_readl_tsr0(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0) - -#define he_writel_tsr1(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1) - -#define he_writel_tsr2(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2) - -#define he_writel_tsr3(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3) - -#define he_writel_tsr4(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4) - - /* from page 2-20 - * - * NOTE While the transmit connection is active, bits 23 through 0 - * of this register must not be written by the host. Byte - * enables should be used during normal operation when writing - * the most significant byte. - */ - -#define he_writel_tsr4_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \ - CON_CTL_TCM \ - | CON_BYTE_DISABLE_2 \ - | CON_BYTE_DISABLE_1 \ - | CON_BYTE_DISABLE_0) - -#define he_readl_tsr4(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4) - -#define he_writel_tsr5(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5) - -#define he_writel_tsr6(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6) - -#define he_writel_tsr7(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7) - - -#define he_writel_tsr8(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0) - -#define he_writel_tsr9(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1) - -#define he_writel_tsr10(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2) - -#define he_writel_tsr11(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3) - - -#define he_writel_tsr12(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0) - -#define he_writel_tsr13(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1) - - -#define he_writel_tsr14(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRD | cid) - -#define he_writel_tsr14_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRD | cid, \ - CON_CTL_TCM \ - | CON_BYTE_DISABLE_2 \ - | CON_BYTE_DISABLE_1 \ - | CON_BYTE_DISABLE_0) - -/* 2.7.1 per connection receive state registers */ - -#define he_writel_rsr0(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0) -#define he_readl_rsr0(dev, cid) \ - he_readl_rcm(dev, 0x00000 | (cid << 3) | 0) - -#define he_writel_rsr1(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1) - -#define he_writel_rsr2(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2) - -#define he_writel_rsr3(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3) - -#define he_writel_rsr4(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4) - -#define he_writel_rsr5(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5) - -#define he_writel_rsr6(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6) - -#define he_writel_rsr7(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) - -static __inline__ struct atm_vcc* -__find_vcc(struct he_dev *he_dev, unsigned cid) -{ - struct hlist_head *head; - struct atm_vcc *vcc; - struct sock *s; - short vpi; - int vci; - - vpi = cid >> he_dev->vcibits; - vci = cid & ((1 << he_dev->vcibits) - 1); - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; - - sk_for_each(s, head) { - vcc = atm_sk(s); - if (vcc->dev == he_dev->atm_dev && - vcc->vci == vci && vcc->vpi == vpi && - vcc->qos.rxtp.traffic_class != ATM_NONE) { - return vcc; - } - } - return NULL; -} - -static int he_init_one(struct pci_dev *pci_dev, - const struct pci_device_id *pci_ent) -{ - struct atm_dev *atm_dev = NULL; - struct he_dev *he_dev = NULL; - int err = 0; - - printk(KERN_INFO "ATM he driver\n"); - - if (pci_enable_device(pci_dev)) - return -EIO; - if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING "he: no suitable dma available\n"); - err = -EIO; - goto init_one_failure; - } - - atm_dev = atm_dev_register(DEV_LABEL, &pci_dev->dev, &he_ops, -1, NULL); - if (!atm_dev) { - err = -ENODEV; - goto init_one_failure; - } - pci_set_drvdata(pci_dev, atm_dev); - - he_dev = kzalloc_obj(struct he_dev); - if (!he_dev) { - err = -ENOMEM; - goto init_one_failure; - } - he_dev->pci_dev = pci_dev; - he_dev->atm_dev = atm_dev; - he_dev->atm_dev->dev_data = he_dev; - atm_dev->dev_data = he_dev; - he_dev->number = atm_dev->number; - tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); - spin_lock_init(&he_dev->global_lock); - - if (he_start(atm_dev)) { - he_stop(he_dev); - err = -ENODEV; - goto init_one_failure; - } - he_dev->next = NULL; - if (he_devs) - he_dev->next = he_devs; - he_devs = he_dev; - return 0; - -init_one_failure: - if (atm_dev) - atm_dev_deregister(atm_dev); - kfree(he_dev); - pci_disable_device(pci_dev); - return err; -} - -static void he_remove_one(struct pci_dev *pci_dev) -{ - struct atm_dev *atm_dev; - struct he_dev *he_dev; - - atm_dev = pci_get_drvdata(pci_dev); - he_dev = HE_DEV(atm_dev); - - /* need to remove from he_devs */ - - he_stop(he_dev); - atm_dev_deregister(atm_dev); - kfree(he_dev); - - pci_disable_device(pci_dev); -} - - -static unsigned -rate_to_atmf(unsigned rate) /* cps to atm forum format */ -{ -#define NONZERO (1 << 14) - - unsigned exp = 0; - - if (rate == 0) - return 0; - - rate <<= 9; - while (rate > 0x3ff) { - ++exp; - rate >>= 1; - } - - return (NONZERO | (exp << 9) | (rate & 0x1ff)); -} - -static void he_init_rx_lbfp0(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; - - lbufd_index = 0; - lbm_offset = he_readl(he_dev, RCMLBM_BA); - - he_writel(he_dev, lbufd_index, RLBF0_H); - - for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { - lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF0_T); - he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); -} - -static void he_init_rx_lbfp1(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; - - lbufd_index = 1; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); - - he_writel(he_dev, lbufd_index, RLBF1_H); - - for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { - lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF1_T); - he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); -} - -static void he_init_tx_lbfp(struct he_dev *he_dev) -{ - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; - - lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); - - he_writel(he_dev, lbufd_index, TLBF_H); - - for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { - lbufd_index += 1; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; - - he_writel_rcm(he_dev, lbuf_addr, lbm_offset); - he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - - if (++lbuf_count == lbufs_per_row) { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } - lbm_offset += 2; - } - - he_writel(he_dev, lbufd_index - 1, TLBF_T); -} - -static int he_init_tpdrq(struct he_dev *he_dev) -{ - he_dev->tpdrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), - &he_dev->tpdrq_phys, - GFP_KERNEL); - if (he_dev->tpdrq_base == NULL) { - hprintk("failed to alloc tpdrq\n"); - return -ENOMEM; - } - - he_dev->tpdrq_tail = he_dev->tpdrq_base; - he_dev->tpdrq_head = he_dev->tpdrq_base; - - he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H); - he_writel(he_dev, 0, TPDRQ_T); - he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S); - - return 0; -} - -static void he_init_cs_block(struct he_dev *he_dev) -{ - unsigned clock, rate, delta; - int reg; - - /* 5.1.7 cs block initialization */ - - for (reg = 0; reg < 0x20; ++reg) - he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg); - - /* rate grid timer reload values */ - - clock = he_is622(he_dev) ? 66667000 : 50000000; - rate = he_dev->atm_dev->link_rate; - delta = rate / 16 / 2; - - for (reg = 0; reg < 0x10; ++reg) { - /* 2.4 internal transmit function - * - * we initialize the first row in the rate grid. - * values are period (in clock cycles) of timer - */ - unsigned period = clock / rate; - - he_writel_mbox(he_dev, period, CS_TGRLD0 + reg); - rate -= delta; - } - - if (he_is622(he_dev)) { - /* table 5.2 (4 cells per lbuf) */ - he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0); - he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1); - he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2); - he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3); - he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4); - - /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ - he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0); - he_writel_mbox(he_dev, 0x1801, CS_ERCTL1); - he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2); - he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); - he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1); - he_writel_mbox(he_dev, 0x14585, CS_RTFWR); - - he_writel_mbox(he_dev, 0x4680, CS_RTATR); - - /* table 5.8 */ - he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET); - he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX); - he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN); - he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC); - he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC); - he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL); - - /* table 5.9 */ - he_writel_mbox(he_dev, 0x5, CS_OTPPER); - he_writel_mbox(he_dev, 0x14, CS_OTWPER); - } else { - /* table 5.1 (4 cells per lbuf) */ - he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0); - he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1); - he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2); - he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3); - he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4); - - /* table 5.3, 5.4, 5.5, 5.6, 5.7 */ - he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0); - he_writel_mbox(he_dev, 0x4701, CS_ERCTL1); - he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2); - he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0); - he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1); - he_writel_mbox(he_dev, 0xf424, CS_RTFWR); - - he_writel_mbox(he_dev, 0x4680, CS_RTATR); - - /* table 5.8 */ - he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET); - he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX); - he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN); - he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC); - he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC); - he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL); - - /* table 5.9 */ - he_writel_mbox(he_dev, 0x6, CS_OTPPER); - he_writel_mbox(he_dev, 0x1e, CS_OTWPER); - } - - he_writel_mbox(he_dev, 0x8, CS_OTTLIM); - - for (reg = 0; reg < 0x8; ++reg) - he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg); - -} - -static int he_init_cs_block_rcm(struct he_dev *he_dev) -{ - unsigned (*rategrid)[16][16]; - unsigned rate, delta; - int i, j, reg; - - unsigned rate_atmf, exp, man; - unsigned long long rate_cps; - int mult, buf, buf_limit = 4; - - rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL); - if (!rategrid) - return -ENOMEM; - - /* initialize rate grid group table */ - - for (reg = 0x0; reg < 0xff; ++reg) - he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); - - /* initialize rate controller groups */ - - for (reg = 0x100; reg < 0x1ff; ++reg) - he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg); - - /* initialize tNrm lookup table */ - - /* the manual makes reference to a routine in a sample driver - for proper configuration; fortunately, we only need this - in order to support abr connection */ - - /* initialize rate to group table */ - - rate = he_dev->atm_dev->link_rate; - delta = rate / 32; - - /* - * 2.4 transmit internal functions - * - * we construct a copy of the rate grid used by the scheduler - * in order to construct the rate to group table below - */ - - for (j = 0; j < 16; j++) { - (*rategrid)[0][j] = rate; - rate -= delta; - } - - for (i = 1; i < 16; i++) - for (j = 0; j < 16; j++) - if (i > 14) - (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4; - else - (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2; - - /* - * 2.4 transmit internal function - * - * this table maps the upper 5 bits of exponent and mantissa - * of the atm forum representation of the rate into an index - * on rate grid - */ - - rate_atmf = 0; - while (rate_atmf < 0x400) { - man = (rate_atmf & 0x1f) << 4; - exp = rate_atmf >> 5; - - /* - instead of '/ 512', use '>> 9' to prevent a call - to divdu3 on x86 platforms - */ - rate_cps = (unsigned long long) (1UL << exp) * (man + 512) >> 9; - - if (rate_cps < 10) - rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */ - - for (i = 255; i > 0; i--) - if ((*rategrid)[i/16][i%16] >= rate_cps) - break; /* pick nearest rate instead? */ - - /* - * each table entry is 16 bits: (rate grid index (8 bits) - * and a buffer limit (8 bits) - * there are two table entries in each 32-bit register - */ - -#ifdef notdef - buf = rate_cps * he_dev->tx_numbuffs / - (he_dev->atm_dev->link_rate * 2); -#else - /* this is pretty, but avoids _divdu3 and is mostly correct */ - mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; - if (rate_cps > (272ULL * mult)) - buf = 4; - else if (rate_cps > (204ULL * mult)) - buf = 3; - else if (rate_cps > (136ULL * mult)) - buf = 2; - else if (rate_cps > (68ULL * mult)) - buf = 1; - else - buf = 0; -#endif - if (buf > buf_limit) - buf = buf_limit; - reg = (reg << 16) | ((i << 8) | buf); - -#define RTGTBL_OFFSET 0x400 - - if (rate_atmf & 0x1) - he_writel_rcm(he_dev, reg, - CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf >> 1)); - - ++rate_atmf; - } - - kfree(rategrid); - return 0; -} - -static int he_init_group(struct he_dev *he_dev, int group) -{ - struct he_buff *heb, *next; - dma_addr_t mapping; - int i; - - he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); - he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), - G0_RBPS_BS + (group * 32)); - - /* bitmap table */ - he_dev->rbpl_table = bitmap_zalloc(RBPL_TABLE_SIZE, GFP_KERNEL); - if (!he_dev->rbpl_table) { - hprintk("unable to allocate rbpl bitmap table\n"); - return -ENOMEM; - } - - /* rbpl_virt 64-bit pointers */ - he_dev->rbpl_virt = kmalloc_objs(*he_dev->rbpl_virt, RBPL_TABLE_SIZE); - if (!he_dev->rbpl_virt) { - hprintk("unable to allocate rbpl virt table\n"); - goto out_free_rbpl_table; - } - - /* large buffer pool */ - he_dev->rbpl_pool = dma_pool_create("rbpl", &he_dev->pci_dev->dev, - CONFIG_RBPL_BUFSIZE, 64, 0); - if (he_dev->rbpl_pool == NULL) { - hprintk("unable to create rbpl pool\n"); - goto out_free_rbpl_virt; - } - - he_dev->rbpl_base = dma_alloc_coherent(&he_dev->pci_dev->dev, - CONFIG_RBPL_SIZE * sizeof(struct he_rbp), - &he_dev->rbpl_phys, GFP_KERNEL); - if (he_dev->rbpl_base == NULL) { - hprintk("failed to alloc rbpl_base\n"); - goto out_destroy_rbpl_pool; - } - - INIT_LIST_HEAD(&he_dev->rbpl_outstanding); - - for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { - - heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL, &mapping); - if (!heb) - goto out_free_rbpl; - heb->mapping = mapping; - list_add(&heb->entry, &he_dev->rbpl_outstanding); - - set_bit(i, he_dev->rbpl_table); - he_dev->rbpl_virt[i] = heb; - he_dev->rbpl_hint = i + 1; - he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET; - he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data); - } - he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; - - he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); - he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), - G0_RBPL_T + (group * 32)); - he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4, - G0_RBPL_BS + (group * 32)); - he_writel(he_dev, - RBP_THRESH(CONFIG_RBPL_THRESH) | - RBP_QSIZE(CONFIG_RBPL_SIZE - 1) | - RBP_INT_ENB, - G0_RBPL_QI + (group * 32)); - - /* rx buffer ready queue */ - - he_dev->rbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, - CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - &he_dev->rbrq_phys, GFP_KERNEL); - if (he_dev->rbrq_base == NULL) { - hprintk("failed to allocate rbrq\n"); - goto out_free_rbpl; - } - - he_dev->rbrq_head = he_dev->rbrq_base; - he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); - he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); - he_writel(he_dev, - RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE - 1), - G0_RBRQ_Q + (group * 16)); - if (irq_coalesce) { - hprintk("coalescing interrupts\n"); - he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), - G0_RBRQ_I + (group * 16)); - } else - he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1), - G0_RBRQ_I + (group * 16)); - - /* tx buffer ready queue */ - - he_dev->tbrq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, - CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - &he_dev->tbrq_phys, GFP_KERNEL); - if (he_dev->tbrq_base == NULL) { - hprintk("failed to allocate tbrq\n"); - goto out_free_rbpq_base; - } - - he_dev->tbrq_head = he_dev->tbrq_base; - - he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16)); - he_writel(he_dev, 0, G0_TBRQ_H + (group * 16)); - he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16)); - he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16)); - - return 0; - -out_free_rbpq_base: - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * - sizeof(struct he_rbrq), he_dev->rbrq_base, - he_dev->rbrq_phys); -out_free_rbpl: - list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) - dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE * - sizeof(struct he_rbp), he_dev->rbpl_base, - he_dev->rbpl_phys); -out_destroy_rbpl_pool: - dma_pool_destroy(he_dev->rbpl_pool); -out_free_rbpl_virt: - kfree(he_dev->rbpl_virt); -out_free_rbpl_table: - bitmap_free(he_dev->rbpl_table); - - return -ENOMEM; -} - -static int he_init_irq(struct he_dev *he_dev) -{ - int i; - - /* 2.9.3.5 tail offset for each interrupt queue is located after the - end of the interrupt queue */ - - he_dev->irq_base = dma_alloc_coherent(&he_dev->pci_dev->dev, - (CONFIG_IRQ_SIZE + 1) * sizeof(struct he_irq), - &he_dev->irq_phys, GFP_KERNEL); - if (he_dev->irq_base == NULL) { - hprintk("failed to allocate irq\n"); - return -ENOMEM; - } - he_dev->irq_tailoffset = (unsigned *) - &he_dev->irq_base[CONFIG_IRQ_SIZE]; - *he_dev->irq_tailoffset = 0; - he_dev->irq_head = he_dev->irq_base; - he_dev->irq_tail = he_dev->irq_base; - - for (i = 0; i < CONFIG_IRQ_SIZE; ++i) - he_dev->irq_base[i].isw = ITYPE_INVALID; - - he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); - he_writel(he_dev, - IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH), - IRQ0_HEAD); - he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL); - he_writel(he_dev, 0x0, IRQ0_DATA); - - he_writel(he_dev, 0x0, IRQ1_BASE); - he_writel(he_dev, 0x0, IRQ1_HEAD); - he_writel(he_dev, 0x0, IRQ1_CNTL); - he_writel(he_dev, 0x0, IRQ1_DATA); - - he_writel(he_dev, 0x0, IRQ2_BASE); - he_writel(he_dev, 0x0, IRQ2_HEAD); - he_writel(he_dev, 0x0, IRQ2_CNTL); - he_writel(he_dev, 0x0, IRQ2_DATA); - - he_writel(he_dev, 0x0, IRQ3_BASE); - he_writel(he_dev, 0x0, IRQ3_HEAD); - he_writel(he_dev, 0x0, IRQ3_CNTL); - he_writel(he_dev, 0x0, IRQ3_DATA); - - /* 2.9.3.2 interrupt queue mapping registers */ - - he_writel(he_dev, 0x0, GRP_10_MAP); - he_writel(he_dev, 0x0, GRP_32_MAP); - he_writel(he_dev, 0x0, GRP_54_MAP); - he_writel(he_dev, 0x0, GRP_76_MAP); - - if (request_irq(he_dev->pci_dev->irq, - he_irq_handler, IRQF_SHARED, DEV_LABEL, he_dev)) { - hprintk("irq %d already in use\n", he_dev->pci_dev->irq); - return -EINVAL; - } - - he_dev->irq = he_dev->pci_dev->irq; - - return 0; -} - -static int he_start(struct atm_dev *dev) -{ - struct he_dev *he_dev; - struct pci_dev *pci_dev; - unsigned long membase; - - u16 command; - u32 gen_cntl_0, host_cntl, lb_swap; - u8 cache_size, timer; - - unsigned err; - unsigned int status, reg; - int i, group; - - he_dev = HE_DEV(dev); - pci_dev = he_dev->pci_dev; - - membase = pci_resource_start(pci_dev, 0); - HPRINTK("membase = 0x%lx irq = %d.\n", membase, pci_dev->irq); - - /* - * pci bus controller initialization - */ - - /* 4.3 pci bus controller-specific initialization */ - if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) { - hprintk("can't read GEN_CNTL_0\n"); - return -EINVAL; - } - gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); - if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) { - hprintk("can't write GEN_CNTL_0.\n"); - return -EINVAL; - } - - if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) { - hprintk("can't read PCI_COMMAND.\n"); - return -EINVAL; - } - - command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); - if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) { - hprintk("can't enable memory.\n"); - return -EINVAL; - } - - if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) { - hprintk("can't read cache line size?\n"); - return -EINVAL; - } - - if (cache_size < 16) { - cache_size = 16; - if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size)) - hprintk("can't set cache line size to %d\n", cache_size); - } - - if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) { - hprintk("can't read latency timer?\n"); - return -EINVAL; - } - - /* from table 3.9 - * - * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE - * - * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles] - * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles] - * - */ -#define LAT_TIMER 209 - if (timer < LAT_TIMER) { - HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER); - timer = LAT_TIMER; - if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer)) - hprintk("can't set latency timer to %d\n", timer); - } - - if (!(he_dev->membase = ioremap(membase, HE_REGMAP_SIZE))) { - hprintk("can't set up page mapping\n"); - return -EINVAL; - } - - /* 4.4 card reset */ - he_writel(he_dev, 0x0, RESET_CNTL); - he_writel(he_dev, 0xff, RESET_CNTL); - - msleep(16); /* 16 ms */ - status = he_readl(he_dev, RESET_CNTL); - if ((status & BOARD_RST_STATUS) == 0) { - hprintk("reset failed\n"); - return -EINVAL; - } - - /* 4.5 set bus width */ - host_cntl = he_readl(he_dev, HOST_CNTL); - if (host_cntl & PCI_BUS_SIZE64) - gen_cntl_0 |= ENBL_64; - else - gen_cntl_0 &= ~ENBL_64; - - if (disable64 == 1) { - hprintk("disabling 64-bit pci bus transfers\n"); - gen_cntl_0 &= ~ENBL_64; - } - - if (gen_cntl_0 & ENBL_64) - hprintk("64-bit transfers enabled\n"); - - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - /* 4.7 read prom contents */ - for (i = 0; i < PROD_ID_LEN; ++i) - he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i); - - he_dev->media = read_prom_byte(he_dev, MEDIA); - - for (i = 0; i < 6; ++i) - dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); - - hprintk("%s%s, %pM\n", he_dev->prod_id, - he_dev->media & 0x40 ? "SM" : "MM", dev->esi); - he_dev->atm_dev->link_rate = he_is622(he_dev) ? - ATM_OC12_PCR : ATM_OC3_PCR; - - /* 4.6 set host endianess */ - lb_swap = he_readl(he_dev, LB_SWAP); - if (he_is622(he_dev)) - lb_swap &= ~XFER_SIZE; /* 4 cells */ - else - lb_swap |= XFER_SIZE; /* 8 cells */ -#ifdef __BIG_ENDIAN - lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST; -#else - lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST | - DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP); -#endif /* __BIG_ENDIAN */ - he_writel(he_dev, lb_swap, LB_SWAP); - - /* 4.8 sdram controller initialization */ - he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL); - - /* 4.9 initialize rnum value */ - lb_swap |= SWAP_RNUM_MAX(0xf); - he_writel(he_dev, lb_swap, LB_SWAP); - - /* 4.10 initialize the interrupt queues */ - if ((err = he_init_irq(he_dev)) != 0) - return err; - - /* 4.11 enable pci bus controller state machines */ - host_cntl |= (OUTFF_ENB | CMDFF_ENB | - QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB); - he_writel(he_dev, host_cntl, HOST_CNTL); - - gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB; - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - /* - * atm network controller initialization - */ - - /* 5.1.1 generic configuration state */ - - /* - * local (cell) buffer memory map - * - * HE155 HE622 - * - * 0 ____________1023 bytes 0 _______________________2047 bytes - * | | | | | - * | utility | | rx0 | | - * 5|____________| 255|___________________| u | - * 6| | 256| | t | - * | | | | i | - * | rx0 | row | tx | l | - * | | | | i | - * | | 767|___________________| t | - * 517|____________| 768| | y | - * row 518| | | rx1 | | - * | | 1023|___________________|___| - * | | - * | tx | - * | | - * | | - * 1535|____________| - * 1536| | - * | rx1 | - * 2047|____________| - * - */ - - /* total 4096 connections */ - he_dev->vcibits = CONFIG_DEFAULT_VCIBITS; - he_dev->vpibits = CONFIG_DEFAULT_VPIBITS; - - if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) { - hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS); - return -ENODEV; - } - - if (nvpibits != -1) { - he_dev->vpibits = nvpibits; - he_dev->vcibits = HE_MAXCIDBITS - nvpibits; - } - - if (nvcibits != -1) { - he_dev->vcibits = nvcibits; - he_dev->vpibits = HE_MAXCIDBITS - nvcibits; - } - - - if (he_is622(he_dev)) { - he_dev->cells_per_row = 40; - he_dev->bytes_per_row = 2048; - he_dev->r0_numrows = 256; - he_dev->tx_numrows = 512; - he_dev->r1_numrows = 256; - he_dev->r0_startrow = 0; - he_dev->tx_startrow = 256; - he_dev->r1_startrow = 768; - } else { - he_dev->cells_per_row = 20; - he_dev->bytes_per_row = 1024; - he_dev->r0_numrows = 512; - he_dev->tx_numrows = 1018; - he_dev->r1_numrows = 512; - he_dev->r0_startrow = 6; - he_dev->tx_startrow = 518; - he_dev->r1_startrow = 1536; - } - - he_dev->cells_per_lbuf = 4; - he_dev->buffer_limit = 4; - he_dev->r0_numbuffs = he_dev->r0_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r0_numbuffs > 2560) - he_dev->r0_numbuffs = 2560; - - he_dev->r1_numbuffs = he_dev->r1_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r1_numbuffs > 2560) - he_dev->r1_numbuffs = 2560; - - he_dev->tx_numbuffs = he_dev->tx_numrows * - he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->tx_numbuffs > 5120) - he_dev->tx_numbuffs = 5120; - - /* 5.1.2 configure hardware dependent registers */ - - he_writel(he_dev, - SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) | - RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) | - (he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) | - (he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)), - LBARB); - - he_writel(he_dev, BANK_ON | - (he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)), - SDRAMCON); - - he_writel(he_dev, - (he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) | - RM_RW_WAIT(1), RCMCONFIG); - he_writel(he_dev, - (he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) | - TM_RW_WAIT(1), TCMCONFIG); - - he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG); - - he_writel(he_dev, - (he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) | - (he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) | - RX_VALVP(he_dev->vpibits) | - RX_VALVC(he_dev->vcibits), RC_CONFIG); - - he_writel(he_dev, DRF_THRESH(0x20) | - (he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) | - TX_VCI_MASK(he_dev->vcibits) | - LBFREE_CNT(he_dev->tx_numbuffs), TX_CONFIG); - - he_writel(he_dev, 0x0, TXAAL5_PROTO); - - he_writel(he_dev, PHY_INT_ENB | - (he_is622(he_dev) ? PTMR_PRE(67 - 1) : PTMR_PRE(50 - 1)), - RH_CONFIG); - - /* 5.1.3 initialize connection memory */ - - for (i = 0; i < TCM_MEM_SIZE; ++i) - he_writel_tcm(he_dev, 0, i); - - for (i = 0; i < RCM_MEM_SIZE; ++i) - he_writel_rcm(he_dev, 0, i); - - /* - * transmit connection memory map - * - * tx memory - * 0x0 ___________________ - * | | - * | | - * | TSRa | - * | | - * | | - * 0x8000|___________________| - * | | - * | TSRb | - * 0xc000|___________________| - * | | - * | TSRc | - * 0xe000|___________________| - * | TSRd | - * 0xf000|___________________| - * | tmABR | - * 0x10000|___________________| - * | | - * | tmTPD | - * |___________________| - * | | - * .... - * 0x1ffff|___________________| - * - * - */ - - he_writel(he_dev, CONFIG_TSRB, TSRB_BA); - he_writel(he_dev, CONFIG_TSRC, TSRC_BA); - he_writel(he_dev, CONFIG_TSRD, TSRD_BA); - he_writel(he_dev, CONFIG_TMABR, TMABR_BA); - he_writel(he_dev, CONFIG_TPDBA, TPD_BA); - - - /* - * receive connection memory map - * - * 0x0 ___________________ - * | | - * | | - * | RSRa | - * | | - * | | - * 0x8000|___________________| - * | | - * | rx0/1 | - * | LBM | link lists of local - * | tx | buffer memory - * | | - * 0xd000|___________________| - * | | - * | rmABR | - * 0xe000|___________________| - * | | - * | RSRb | - * |___________________| - * | | - * .... - * 0xffff|___________________| - */ - - he_writel(he_dev, 0x08000, RCMLBM_BA); - he_writel(he_dev, 0x0e000, RCMRSRB_BA); - he_writel(he_dev, 0x0d800, RCMABR_BA); - - /* 5.1.4 initialize local buffer free pools linked lists */ - - he_init_rx_lbfp0(he_dev); - he_init_rx_lbfp1(he_dev); - - he_writel(he_dev, 0x0, RLBC_H); - he_writel(he_dev, 0x0, RLBC_T); - he_writel(he_dev, 0x0, RLBC_H2); - - he_writel(he_dev, 512, RXTHRSH); /* 10% of r0+r1 buffers */ - he_writel(he_dev, 256, LITHRSH); /* 5% of r0+r1 buffers */ - - he_init_tx_lbfp(he_dev); - - he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA); - - /* 5.1.5 initialize intermediate receive queues */ - - if (he_is622(he_dev)) { - he_writel(he_dev, 0x000f, G0_INMQ_S); - he_writel(he_dev, 0x200f, G0_INMQ_L); - - he_writel(he_dev, 0x001f, G1_INMQ_S); - he_writel(he_dev, 0x201f, G1_INMQ_L); - - he_writel(he_dev, 0x002f, G2_INMQ_S); - he_writel(he_dev, 0x202f, G2_INMQ_L); - - he_writel(he_dev, 0x003f, G3_INMQ_S); - he_writel(he_dev, 0x203f, G3_INMQ_L); - - he_writel(he_dev, 0x004f, G4_INMQ_S); - he_writel(he_dev, 0x204f, G4_INMQ_L); - - he_writel(he_dev, 0x005f, G5_INMQ_S); - he_writel(he_dev, 0x205f, G5_INMQ_L); - - he_writel(he_dev, 0x006f, G6_INMQ_S); - he_writel(he_dev, 0x206f, G6_INMQ_L); - - he_writel(he_dev, 0x007f, G7_INMQ_S); - he_writel(he_dev, 0x207f, G7_INMQ_L); - } else { - he_writel(he_dev, 0x0000, G0_INMQ_S); - he_writel(he_dev, 0x0008, G0_INMQ_L); - - he_writel(he_dev, 0x0001, G1_INMQ_S); - he_writel(he_dev, 0x0009, G1_INMQ_L); - - he_writel(he_dev, 0x0002, G2_INMQ_S); - he_writel(he_dev, 0x000a, G2_INMQ_L); - - he_writel(he_dev, 0x0003, G3_INMQ_S); - he_writel(he_dev, 0x000b, G3_INMQ_L); - - he_writel(he_dev, 0x0004, G4_INMQ_S); - he_writel(he_dev, 0x000c, G4_INMQ_L); - - he_writel(he_dev, 0x0005, G5_INMQ_S); - he_writel(he_dev, 0x000d, G5_INMQ_L); - - he_writel(he_dev, 0x0006, G6_INMQ_S); - he_writel(he_dev, 0x000e, G6_INMQ_L); - - he_writel(he_dev, 0x0007, G7_INMQ_S); - he_writel(he_dev, 0x000f, G7_INMQ_L); - } - - /* 5.1.6 application tunable parameters */ - - he_writel(he_dev, 0x0, MCC); - he_writel(he_dev, 0x0, OEC); - he_writel(he_dev, 0x0, DCC); - he_writel(he_dev, 0x0, CEC); - - /* 5.1.7 cs block initialization */ - - he_init_cs_block(he_dev); - - /* 5.1.8 cs block connection memory initialization */ - - if (he_init_cs_block_rcm(he_dev) < 0) - return -ENOMEM; - - /* 5.1.10 initialize host structures */ - - he_init_tpdrq(he_dev); - - he_dev->tpd_pool = dma_pool_create("tpd", &he_dev->pci_dev->dev, - sizeof(struct he_tpd), TPD_ALIGNMENT, 0); - if (he_dev->tpd_pool == NULL) { - hprintk("unable to create tpd dma_pool\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&he_dev->outstanding_tpds); - - if (he_init_group(he_dev, 0) != 0) - return -ENOMEM; - - for (group = 1; group < HE_NUM_GROUPS; ++group) { - he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); - he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), - G0_RBPS_BS + (group * 32)); - - he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32)); - he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0), - G0_RBPL_QI + (group * 32)); - he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32)); - - he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16)); - he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16)); - he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0), - G0_RBRQ_Q + (group * 16)); - he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16)); - - he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16)); - he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16)); - he_writel(he_dev, TBRQ_THRESH(0x1), - G0_TBRQ_THRESH + (group * 16)); - he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16)); - } - - /* host status page */ - - he_dev->hsp = dma_alloc_coherent(&he_dev->pci_dev->dev, - sizeof(struct he_hsp), - &he_dev->hsp_phys, GFP_KERNEL); - if (he_dev->hsp == NULL) { - hprintk("failed to allocate host status page\n"); - return -ENOMEM; - } - he_writel(he_dev, he_dev->hsp_phys, HSP_BA); - - /* initialize framer */ - -#ifdef CONFIG_ATM_HE_USE_SUNI - if (he_isMM(he_dev)) - suni_init(he_dev->atm_dev); - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start) - he_dev->atm_dev->phy->start(he_dev->atm_dev); -#endif /* CONFIG_ATM_HE_USE_SUNI */ - - if (sdh) { - /* this really should be in suni.c but for now... */ - int val; - - val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM); - val = (val & ~SUNI_TPOP_APM_S) | (SUNI_TPOP_S_SDH << SUNI_TPOP_APM_S_SHIFT); - he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM); - he_phy_put(he_dev->atm_dev, SUNI_TACP_IUCHP_CLP, SUNI_TACP_IUCHP); - } - - /* 5.1.12 enable transmit and receive */ - - reg = he_readl_mbox(he_dev, CS_ERCTL0); - reg |= TX_ENABLE|ER_ENABLE; - he_writel_mbox(he_dev, reg, CS_ERCTL0); - - reg = he_readl(he_dev, RC_CONFIG); - reg |= RX_ENABLE; - he_writel(he_dev, reg, RC_CONFIG); - - for (i = 0; i < HE_NUM_CS_STPER; ++i) { - he_dev->cs_stper[i].inuse = 0; - he_dev->cs_stper[i].pcr = -1; - } - he_dev->total_bw = 0; - - - /* atm linux initialization */ - - he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits; - he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits; - - he_dev->irq_peak = 0; - he_dev->rbrq_peak = 0; - he_dev->rbpl_peak = 0; - he_dev->tbrq_peak = 0; - - HPRINTK("hell bent for leather!\n"); - - return 0; -} - -static void -he_stop(struct he_dev *he_dev) -{ - struct he_buff *heb, *next; - struct pci_dev *pci_dev; - u32 gen_cntl_0, reg; - u16 command; - - pci_dev = he_dev->pci_dev; - - /* disable interrupts */ - - if (he_dev->membase) { - pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0); - gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); - pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); - - tasklet_disable(&he_dev->tasklet); - - /* disable recv and transmit */ - - reg = he_readl_mbox(he_dev, CS_ERCTL0); - reg &= ~(TX_ENABLE|ER_ENABLE); - he_writel_mbox(he_dev, reg, CS_ERCTL0); - - reg = he_readl(he_dev, RC_CONFIG); - reg &= ~(RX_ENABLE); - he_writel(he_dev, reg, RC_CONFIG); - } - -#ifdef CONFIG_ATM_HE_USE_SUNI - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop) - he_dev->atm_dev->phy->stop(he_dev->atm_dev); -#endif /* CONFIG_ATM_HE_USE_SUNI */ - - if (he_dev->irq) - free_irq(he_dev->irq, he_dev); - - if (he_dev->irq_base) - dma_free_coherent(&he_dev->pci_dev->dev, (CONFIG_IRQ_SIZE + 1) - * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys); - - if (he_dev->hsp) - dma_free_coherent(&he_dev->pci_dev->dev, sizeof(struct he_hsp), - he_dev->hsp, he_dev->hsp_phys); - - if (he_dev->rbpl_base) { - list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry) - dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE - * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys); - } - - kfree(he_dev->rbpl_virt); - bitmap_free(he_dev->rbpl_table); - dma_pool_destroy(he_dev->rbpl_pool); - - if (he_dev->rbrq_base) - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), - he_dev->rbrq_base, he_dev->rbrq_phys); - - if (he_dev->tbrq_base) - dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), - he_dev->tbrq_base, he_dev->tbrq_phys); - - if (he_dev->tpdrq_base) - dma_free_coherent(&he_dev->pci_dev->dev, - CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), - he_dev->tpdrq_base, he_dev->tpdrq_phys); - - dma_pool_destroy(he_dev->tpd_pool); - - if (he_dev->pci_dev) { - pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); - command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command); - } - - if (he_dev->membase) - iounmap(he_dev->membase); -} - -static struct he_tpd * -__alloc_tpd(struct he_dev *he_dev) -{ - struct he_tpd *tpd; - dma_addr_t mapping; - - tpd = dma_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC, &mapping); - if (tpd == NULL) - return NULL; - - tpd->status = TPD_ADDR(mapping); - tpd->reserved = 0; - tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0; - tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0; - tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0; - - return tpd; -} - -#define AAL5_LEN(buf,len) \ - ((((unsigned char *)(buf))[(len)-6] << 8) | \ - (((unsigned char *)(buf))[(len)-5])) - -/* 2.10.1.2 receive - * - * aal5 packets can optionally return the tcp checksum in the lower - * 16 bits of the crc (RSR0_TCP_CKSUM) - */ - -#define TCP_CKSUM(buf,len) \ - ((((unsigned char *)(buf))[(len)-2] << 8) | \ - (((unsigned char *)(buf))[(len-1)])) - -static int -he_service_rbrq(struct he_dev *he_dev, int group) -{ - struct he_rbrq *rbrq_tail = (struct he_rbrq *) - ((unsigned long)he_dev->rbrq_base | - he_dev->hsp->group[group].rbrq_tail); - unsigned cid, lastcid = -1; - struct sk_buff *skb; - struct atm_vcc *vcc = NULL; - struct he_vcc *he_vcc; - struct he_buff *heb, *next; - int i; - int pdus_assembled = 0; - int updated = 0; - - read_lock(&vcc_sklist_lock); - while (he_dev->rbrq_head != rbrq_tail) { - ++updated; - - HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n", - he_dev->rbrq_head, group, - RBRQ_ADDR(he_dev->rbrq_head), - RBRQ_BUFLEN(he_dev->rbrq_head), - RBRQ_CID(he_dev->rbrq_head), - RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "", - RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "", - RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "", - RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "", - RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "", - RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : ""); - - i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET; - heb = he_dev->rbpl_virt[i]; - - cid = RBRQ_CID(he_dev->rbrq_head); - if (cid != lastcid) - vcc = __find_vcc(he_dev, cid); - lastcid = cid; - - if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) { - hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid); - if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) { - clear_bit(i, he_dev->rbpl_table); - list_del(&heb->entry); - dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - } - - goto next_rbrq_entry; - } - - if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) { - hprintk("HBUF_ERR! (cid 0x%x)\n", cid); - atomic_inc(&vcc->stats->rx_drop); - goto return_host_buffers; - } - - heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4; - clear_bit(i, he_dev->rbpl_table); - list_move_tail(&heb->entry, &he_vcc->buffers); - he_vcc->pdu_len += heb->len; - - if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) { - lastcid = -1; - HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid); - wake_up(&he_vcc->rx_waitq); - goto return_host_buffers; - } - - if (!RBRQ_END_PDU(he_dev->rbrq_head)) - goto next_rbrq_entry; - - if (RBRQ_LEN_ERR(he_dev->rbrq_head) - || RBRQ_CRC_ERR(he_dev->rbrq_head)) { - HPRINTK("%s%s (%d.%d)\n", - RBRQ_CRC_ERR(he_dev->rbrq_head) - ? "CRC_ERR " : "", - RBRQ_LEN_ERR(he_dev->rbrq_head) - ? "LEN_ERR" : "", - vcc->vpi, vcc->vci); - atomic_inc(&vcc->stats->rx_err); - goto return_host_buffers; - } - - skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve, - GFP_ATOMIC); - if (!skb) { - HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci); - goto return_host_buffers; - } - - if (rx_skb_reserve > 0) - skb_reserve(skb, rx_skb_reserve); - - __net_timestamp(skb); - - list_for_each_entry(heb, &he_vcc->buffers, entry) - skb_put_data(skb, &heb->data, heb->len); - - switch (vcc->qos.aal) { - case ATM_AAL0: - /* 2.10.1.5 raw cell receive */ - skb->len = ATM_AAL0_SDU; - skb_set_tail_pointer(skb, skb->len); - break; - case ATM_AAL5: - /* 2.10.1.2 aal5 receive */ - - skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); - skb_set_tail_pointer(skb, skb->len); -#ifdef USE_CHECKSUM_HW - if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = TCP_CKSUM(skb->data, - he_vcc->pdu_len); - } -#endif - break; - } - -#ifdef should_never_happen - if (skb->len > vcc->qos.rxtp.max_sdu) - hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)! cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid); -#endif - -#ifdef notdef - ATM_SKB(skb)->vcc = vcc; -#endif - spin_unlock(&he_dev->global_lock); - vcc->push(vcc, skb); - spin_lock(&he_dev->global_lock); - - atomic_inc(&vcc->stats->rx); - -return_host_buffers: - ++pdus_assembled; - - list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry) - dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping); - INIT_LIST_HEAD(&he_vcc->buffers); - he_vcc->pdu_len = 0; - -next_rbrq_entry: - he_dev->rbrq_head = (struct he_rbrq *) - ((unsigned long) he_dev->rbrq_base | - RBRQ_MASK(he_dev->rbrq_head + 1)); - - } - read_unlock(&vcc_sklist_lock); - - if (updated) { - if (updated > he_dev->rbrq_peak) - he_dev->rbrq_peak = updated; - - he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head), - G0_RBRQ_H + (group * 16)); - } - - return pdus_assembled; -} - -static void -he_service_tbrq(struct he_dev *he_dev, int group) -{ - struct he_tbrq *tbrq_tail = (struct he_tbrq *) - ((unsigned long)he_dev->tbrq_base | - he_dev->hsp->group[group].tbrq_tail); - struct he_tpd *tpd; - int slot, updated = 0; - struct he_tpd *__tpd; - - /* 2.1.6 transmit buffer return queue */ - - while (he_dev->tbrq_head != tbrq_tail) { - ++updated; - - HPRINTK("tbrq%d 0x%x%s%s\n", - group, - TBRQ_TPD(he_dev->tbrq_head), - TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "", - TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : ""); - tpd = NULL; - list_for_each_entry(__tpd, &he_dev->outstanding_tpds, entry) { - if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { - tpd = __tpd; - list_del(&__tpd->entry); - break; - } - } - - if (tpd == NULL) { - hprintk("unable to locate tpd for dma buffer %x\n", - TBRQ_TPD(he_dev->tbrq_head)); - goto next_tbrq_entry; - } - - if (TBRQ_EOS(he_dev->tbrq_head)) { - HPRINTK("wake_up(tx_waitq) cid 0x%x\n", - he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci)); - if (tpd->vcc) - wake_up(&HE_VCC(tpd->vcc)->tx_waitq); - - goto next_tbrq_entry; - } - - for (slot = 0; slot < TPD_MAXIOV; ++slot) { - if (tpd->iovec[slot].addr) - dma_unmap_single(&he_dev->pci_dev->dev, - tpd->iovec[slot].addr, - tpd->iovec[slot].len & TPD_LEN_MASK, - DMA_TO_DEVICE); - if (tpd->iovec[slot].len & TPD_LST) - break; - - } - - if (tpd->skb) { /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ - if (tpd->vcc && tpd->vcc->pop) - tpd->vcc->pop(tpd->vcc, tpd->skb); - else - dev_kfree_skb_any(tpd->skb); - } - -next_tbrq_entry: - if (tpd) - dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); - he_dev->tbrq_head = (struct he_tbrq *) - ((unsigned long) he_dev->tbrq_base | - TBRQ_MASK(he_dev->tbrq_head + 1)); - } - - if (updated) { - if (updated > he_dev->tbrq_peak) - he_dev->tbrq_peak = updated; - - he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head), - G0_TBRQ_H + (group * 16)); - } -} - -static void -he_service_rbpl(struct he_dev *he_dev, int group) -{ - struct he_rbp *new_tail; - struct he_rbp *rbpl_head; - struct he_buff *heb; - dma_addr_t mapping; - int i; - int moved = 0; - - rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | - RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); - - for (;;) { - new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | - RBPL_MASK(he_dev->rbpl_tail+1)); - - /* table 3.42 -- rbpl_tail should never be set to rbpl_head */ - if (new_tail == rbpl_head) - break; - - i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint); - if (i > (RBPL_TABLE_SIZE - 1)) { - i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE); - if (i > (RBPL_TABLE_SIZE - 1)) - break; - } - he_dev->rbpl_hint = i + 1; - - heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC, &mapping); - if (!heb) - break; - heb->mapping = mapping; - list_add(&heb->entry, &he_dev->rbpl_outstanding); - he_dev->rbpl_virt[i] = heb; - set_bit(i, he_dev->rbpl_table); - new_tail->idx = i << RBP_IDX_OFFSET; - new_tail->phys = mapping + offsetof(struct he_buff, data); - - he_dev->rbpl_tail = new_tail; - ++moved; - } - - if (moved) - he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); -} - -static void -he_tasklet(unsigned long data) -{ - unsigned long flags; - struct he_dev *he_dev = (struct he_dev *) data; - int group, type; - int updated = 0; - - HPRINTK("tasklet (0x%lx)\n", data); - spin_lock_irqsave(&he_dev->global_lock, flags); - - while (he_dev->irq_head != he_dev->irq_tail) { - ++updated; - - type = ITYPE_TYPE(he_dev->irq_head->isw); - group = ITYPE_GROUP(he_dev->irq_head->isw); - - switch (type) { - case ITYPE_RBRQ_THRESH: - HPRINTK("rbrq%d threshold\n", group); - fallthrough; - case ITYPE_RBRQ_TIMER: - if (he_service_rbrq(he_dev, group)) - he_service_rbpl(he_dev, group); - break; - case ITYPE_TBRQ_THRESH: - HPRINTK("tbrq%d threshold\n", group); - fallthrough; - case ITYPE_TPD_COMPLETE: - he_service_tbrq(he_dev, group); - break; - case ITYPE_RBPL_THRESH: - he_service_rbpl(he_dev, group); - break; - case ITYPE_RBPS_THRESH: - /* shouldn't happen unless small buffers enabled */ - break; - case ITYPE_PHY: - HPRINTK("phy interrupt\n"); -#ifdef CONFIG_ATM_HE_USE_SUNI - spin_unlock_irqrestore(&he_dev->global_lock, flags); - if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) - he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); - spin_lock_irqsave(&he_dev->global_lock, flags); -#endif - break; - case ITYPE_OTHER: - switch (type|group) { - case ITYPE_PARITY: - hprintk("parity error\n"); - break; - case ITYPE_ABORT: - hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR)); - break; - } - break; - case ITYPE_TYPE(ITYPE_INVALID): - /* see 8.1.1 -- check all queues */ - - HPRINTK("isw not updated 0x%x\n", he_dev->irq_head->isw); - - he_service_rbrq(he_dev, 0); - he_service_rbpl(he_dev, 0); - he_service_tbrq(he_dev, 0); - break; - default: - hprintk("bad isw 0x%x?\n", he_dev->irq_head->isw); - } - - he_dev->irq_head->isw = ITYPE_INVALID; - - he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK); - } - - if (updated) { - if (updated > he_dev->irq_peak) - he_dev->irq_peak = updated; - - he_writel(he_dev, - IRQ_SIZE(CONFIG_IRQ_SIZE) | - IRQ_THRESH(CONFIG_IRQ_THRESH) | - IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD); - (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata; flush posted writes */ - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); -} - -static irqreturn_t -he_irq_handler(int irq, void *dev_id) -{ - unsigned long flags; - struct he_dev *he_dev = (struct he_dev * )dev_id; - int handled = 0; - - if (he_dev == NULL) - return IRQ_NONE; - - spin_lock_irqsave(&he_dev->global_lock, flags); - - he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | - (*he_dev->irq_tailoffset << 2)); - - if (he_dev->irq_tail == he_dev->irq_head) { - HPRINTK("tailoffset not updated?\n"); - he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | - ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); - (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ - } - -#ifdef DEBUG - if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */) - hprintk("spurious (or shared) interrupt?\n"); -#endif - - if (he_dev->irq_head != he_dev->irq_tail) { - handled = 1; - tasklet_schedule(&he_dev->tasklet); - he_writel(he_dev, INT_CLEAR_A, INT_FIFO); /* clear interrupt */ - (void) he_readl(he_dev, INT_FIFO); /* flush posted writes */ - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return IRQ_RETVAL(handled); - -} - -static __inline__ void -__enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid) -{ - struct he_tpdrq *new_tail; - - HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n", - tpd, cid, he_dev->tpdrq_tail); - - /* new_tail = he_dev->tpdrq_tail; */ - new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base | - TPDRQ_MASK(he_dev->tpdrq_tail+1)); - - /* - * check to see if we are about to set the tail == head - * if true, update the head pointer from the adapter - * to see if this is really the case (reading the queue - * head for every enqueue would be unnecessarily slow) - */ - - if (new_tail == he_dev->tpdrq_head) { - he_dev->tpdrq_head = (struct he_tpdrq *) - (((unsigned long)he_dev->tpdrq_base) | - TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H))); - - if (new_tail == he_dev->tpdrq_head) { - int slot; - - hprintk("tpdrq full (cid 0x%x)\n", cid); - /* - * FIXME - * push tpd onto a transmit backlog queue - * after service_tbrq, service the backlog - * for now, we just drop the pdu - */ - for (slot = 0; slot < TPD_MAXIOV; ++slot) { - if (tpd->iovec[slot].addr) - dma_unmap_single(&he_dev->pci_dev->dev, - tpd->iovec[slot].addr, - tpd->iovec[slot].len & TPD_LEN_MASK, - DMA_TO_DEVICE); - } - if (tpd->skb) { - if (tpd->vcc->pop) - tpd->vcc->pop(tpd->vcc, tpd->skb); - else - dev_kfree_skb_any(tpd->skb); - atomic_inc(&tpd->vcc->stats->tx_err); - } - dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); - return; - } - } - - /* 2.1.5 transmit packet descriptor ready queue */ - list_add_tail(&tpd->entry, &he_dev->outstanding_tpds); - he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status); - he_dev->tpdrq_tail->cid = cid; - wmb(); - - he_dev->tpdrq_tail = new_tail; - - he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T); - (void) he_readl(he_dev, TPDRQ_T); /* flush posted writes */ -} - -static int -he_open(struct atm_vcc *vcc) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(vcc->dev); - struct he_vcc *he_vcc; - int err = 0; - unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock; - short vpi = vcc->vpi; - int vci = vcc->vci; - - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) - return 0; - - HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci); - - set_bit(ATM_VF_ADDR, &vcc->flags); - - cid = he_mkcid(he_dev, vpi, vci); - - he_vcc = kmalloc_obj(struct he_vcc, GFP_ATOMIC); - if (he_vcc == NULL) { - hprintk("unable to allocate he_vcc during open\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&he_vcc->buffers); - he_vcc->pdu_len = 0; - he_vcc->rc_index = -1; - - init_waitqueue_head(&he_vcc->rx_waitq); - init_waitqueue_head(&he_vcc->tx_waitq); - - vcc->dev_data = he_vcc; - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - int pcr_goal; - - pcr_goal = atm_pcr_goal(&vcc->qos.txtp); - if (pcr_goal == 0) - pcr_goal = he_dev->atm_dev->link_rate; - if (pcr_goal < 0) /* means round down, technically */ - pcr_goal = -pcr_goal; - - HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); - - switch (vcc->qos.aal) { - case ATM_AAL5: - tsr0_aal = TSR0_AAL5; - tsr4 = TSR4_AAL5; - break; - case ATM_AAL0: - tsr0_aal = TSR0_AAL0_SDU; - tsr4 = TSR4_AAL0_SDU; - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - tsr0 = he_readl_tsr0(he_dev, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - if (TSR0_CONN_STATE(tsr0) != 0) { - hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); - err = -EBUSY; - goto open_failed; - } - - switch (vcc->qos.txtp.traffic_class) { - case ATM_UBR: - /* 2.3.3.1 open connection ubr */ - - tsr0 = TSR0_UBR | TSR0_GROUP(0) | tsr0_aal | - TSR0_USE_WMIN | TSR0_UPDATE_GER; - break; - - case ATM_CBR: - /* 2.3.3.2 open connection cbr */ - - /* 8.2.3 cbr scheduler wrap problem -- limit to 90% total link rate */ - if ((he_dev->total_bw + pcr_goal) - > (he_dev->atm_dev->link_rate * 9 / 10)) - { - err = -EBUSY; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); /* also protects he_dev->cs_stper[] */ - - /* find an unused cs_stper register */ - for (reg = 0; reg < HE_NUM_CS_STPER; ++reg) - if (he_dev->cs_stper[reg].inuse == 0 || - he_dev->cs_stper[reg].pcr == pcr_goal) - break; - - if (reg == HE_NUM_CS_STPER) { - err = -EBUSY; - spin_unlock_irqrestore(&he_dev->global_lock, flags); - goto open_failed; - } - - he_dev->total_bw += pcr_goal; - - he_vcc->rc_index = reg; - ++he_dev->cs_stper[reg].inuse; - he_dev->cs_stper[reg].pcr = pcr_goal; - - clock = he_is622(he_dev) ? 66667000 : 50000000; - period = clock / pcr_goal; - - HPRINTK("rc_index = %d period = %d\n", - reg, period); - - he_writel_mbox(he_dev, rate_to_atmf(period/2), - CS_STPER0 + reg); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | - TSR0_RC_INDEX(reg); - - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - - he_writel_tsr0(he_dev, tsr0, cid); - he_writel_tsr4(he_dev, tsr4 | 1, cid); - he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) | - TSR1_PCR(rate_to_atmf(pcr_goal)), cid); - he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid); - he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid); - - he_writel_tsr3(he_dev, 0x0, cid); - he_writel_tsr5(he_dev, 0x0, cid); - he_writel_tsr6(he_dev, 0x0, cid); - he_writel_tsr7(he_dev, 0x0, cid); - he_writel_tsr8(he_dev, 0x0, cid); - he_writel_tsr10(he_dev, 0x0, cid); - he_writel_tsr11(he_dev, 0x0, cid); - he_writel_tsr12(he_dev, 0x0, cid); - he_writel_tsr13(he_dev, 0x0, cid); - he_writel_tsr14(he_dev, 0x0, cid); - (void) he_readl_tsr0(he_dev, cid); /* flush posted writes */ - spin_unlock_irqrestore(&he_dev->global_lock, flags); - } - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - unsigned aal; - - HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid, - &HE_VCC(vcc)->rx_waitq); - - switch (vcc->qos.aal) { - case ATM_AAL5: - aal = RSR0_AAL5; - break; - case ATM_AAL0: - aal = RSR0_RAWCELL; - break; - default: - err = -EINVAL; - goto open_failed; - } - - spin_lock_irqsave(&he_dev->global_lock, flags); - - rsr0 = he_readl_rsr0(he_dev, cid); - if (rsr0 & RSR0_OPEN_CONN) { - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); - err = -EBUSY; - goto open_failed; - } - - rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY; - rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY; - rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? - (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; - -#ifdef USE_CHECKSUM_HW - if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) - rsr0 |= RSR0_TCP_CKSUM; -#endif - - he_writel_rsr4(he_dev, rsr4, cid); - he_writel_rsr1(he_dev, rsr1, cid); - /* 5.1.11 last parameter initialized should be - the open/closed indication in rsr0 */ - he_writel_rsr0(he_dev, - rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); - (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ - - spin_unlock_irqrestore(&he_dev->global_lock, flags); - } - -open_failed: - - if (err) { - kfree(he_vcc); - clear_bit(ATM_VF_ADDR, &vcc->flags); - } - else - set_bit(ATM_VF_READY, &vcc->flags); - - return err; -} - -static void -he_close(struct atm_vcc *vcc) -{ - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - struct he_dev *he_dev = HE_DEV(vcc->dev); - struct he_tpd *tpd; - unsigned cid; - struct he_vcc *he_vcc = HE_VCC(vcc); -#define MAX_RETRY 30 - int retry = 0, sleep = 1, tx_inuse; - - HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci); - - clear_bit(ATM_VF_READY, &vcc->flags); - cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - int timeout; - - HPRINTK("close rx cid 0x%x\n", cid); - - /* 2.7.2.2 close receive operation */ - - /* wait for previous close (if any) to finish */ - - spin_lock_irqsave(&he_dev->global_lock, flags); - while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) { - HPRINTK("close cid 0x%x RCC_BUSY\n", cid); - udelay(250); - } - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&he_vcc->rx_waitq, &wait); - - he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid); - (void) he_readl_rsr0(he_dev, cid); /* flush posted writes */ - he_writel_mbox(he_dev, cid, RXCON_CLOSE); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - timeout = schedule_timeout(30*HZ); - - remove_wait_queue(&he_vcc->rx_waitq, &wait); - set_current_state(TASK_RUNNING); - - if (timeout == 0) - hprintk("close rx timeout cid 0x%x\n", cid); - - HPRINTK("close rx cid 0x%x complete\n", cid); - - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - volatile unsigned tsr4, tsr0; - int timeout; - - HPRINTK("close tx cid 0x%x\n", cid); - - /* 2.1.2 - * - * ... the host must first stop queueing packets to the TPDRQ - * on the connection to be closed, then wait for all outstanding - * packets to be transmitted and their buffers returned to the - * TBRQ. When the last packet on the connection arrives in the - * TBRQ, the host issues the close command to the adapter. - */ - - while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) && - (retry < MAX_RETRY)) { - msleep(sleep); - if (sleep < 250) - sleep = sleep * 2; - - ++retry; - } - - if (tx_inuse > 1) - hprintk("close tx cid 0x%x tx_inuse = %d\n", cid, tx_inuse); - - /* 2.3.1.1 generic close operations with flush */ - - spin_lock_irqsave(&he_dev->global_lock, flags); - he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); - /* also clears TSR4_SESSION_ENDED */ - - switch (vcc->qos.txtp.traffic_class) { - case ATM_UBR: - he_writel_tsr1(he_dev, - TSR1_MCR(rate_to_atmf(200000)) - | TSR1_PCR(0), cid); - break; - case ATM_CBR: - he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid); - break; - } - (void) he_readl_tsr4(he_dev, cid); /* flush posted writes */ - - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid); - goto close_tx_incomplete; - } - tpd->status |= TPD_EOS | TPD_INT; - tpd->skb = NULL; - tpd->vcc = vcc; - wmb(); - - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&he_vcc->tx_waitq, &wait); - __enqueue_tpd(he_dev, tpd, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - timeout = schedule_timeout(30*HZ); - - remove_wait_queue(&he_vcc->tx_waitq, &wait); - set_current_state(TASK_RUNNING); - - spin_lock_irqsave(&he_dev->global_lock, flags); - - if (timeout == 0) { - hprintk("close tx timeout cid 0x%x\n", cid); - goto close_tx_incomplete; - } - - while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { - HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); - udelay(250); - } - - while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) { - HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0); - udelay(250); - } - -close_tx_incomplete: - - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - int reg = he_vcc->rc_index; - - HPRINTK("cs_stper reg = %d\n", reg); - - if (he_dev->cs_stper[reg].inuse == 0) - hprintk("cs_stper[%d].inuse = 0!\n", reg); - else - --he_dev->cs_stper[reg].inuse; - - he_dev->total_bw -= he_dev->cs_stper[reg].pcr; - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - HPRINTK("close tx cid 0x%x complete\n", cid); - } - - kfree(he_vcc); - - clear_bit(ATM_VF_ADDR, &vcc->flags); -} - -static int -he_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(vcc->dev); - unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); - struct he_tpd *tpd; -#ifdef USE_SCATTERGATHER - int i, slot = 0; -#endif - -#define HE_TPD_BUFSIZE 0xffff - - HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci); - - if ((skb->len > HE_TPD_BUFSIZE) || - ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) { - hprintk("buffer too large (or small) -- %d bytes\n", skb->len ); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - return -EINVAL; - } - -#ifndef USE_SCATTERGATHER - if (skb_shinfo(skb)->nr_frags) { - hprintk("no scatter/gather support\n"); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - return -EINVAL; - } -#endif - spin_lock_irqsave(&he_dev->global_lock, flags); - - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return -ENOMEM; - } - - if (vcc->qos.aal == ATM_AAL5) - tpd->status |= TPD_CELLTYPE(TPD_USERCELL); - else { - char *pti_clp = (void *) (skb->data + 3); - int clp, pti; - - pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; - clp = (*pti_clp & ATM_HDR_CLP); - tpd->status |= TPD_CELLTYPE(pti); - if (clp) - tpd->status |= TPD_CLP; - - skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD); - } - -#ifdef USE_SCATTERGATHER - tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); - tpd->iovec[slot].len = skb_headlen(skb); - ++slot; - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - if (slot == TPD_MAXIOV) { /* queue tpd; start new tpd */ - tpd->vcc = vcc; - tpd->skb = NULL; /* not the last fragment - so dont ->push() yet */ - wmb(); - - __enqueue_tpd(he_dev, tpd, cid); - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) { - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - atomic_inc(&vcc->stats->tx_err); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - return -ENOMEM; - } - tpd->status |= TPD_USERCELL; - slot = 0; - } - - tpd->iovec[slot].addr = skb_frag_dma_map(&he_dev->pci_dev->dev, - frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); - tpd->iovec[slot].len = skb_frag_size(frag); - ++slot; - - } - - tpd->iovec[slot - 1].len |= TPD_LST; -#else - tpd->address0 = dma_map_single(&he_dev->pci_dev->dev, skb->data, skb->len, DMA_TO_DEVICE); - tpd->length0 = skb->len | TPD_LST; -#endif - tpd->status |= TPD_INT; - - tpd->vcc = vcc; - tpd->skb = skb; - wmb(); - ATM_SKB(skb)->vcc = vcc; - - __enqueue_tpd(he_dev, tpd, cid); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - atomic_inc(&vcc->stats->tx); - - return 0; -} - -static int -he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - struct he_ioctl_reg reg; - int err = 0; - - switch (cmd) { - case HE_GET_REG: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(®, arg, - sizeof(struct he_ioctl_reg))) - return -EFAULT; - - spin_lock_irqsave(&he_dev->global_lock, flags); - switch (reg.type) { - case HE_REGTYPE_PCI: - if (reg.addr >= HE_REGMAP_SIZE) { - err = -EINVAL; - break; - } - - reg.val = he_readl(he_dev, reg.addr); - break; - case HE_REGTYPE_RCM: - reg.val = - he_readl_rcm(he_dev, reg.addr); - break; - case HE_REGTYPE_TCM: - reg.val = - he_readl_tcm(he_dev, reg.addr); - break; - case HE_REGTYPE_MBOX: - reg.val = - he_readl_mbox(he_dev, reg.addr); - break; - default: - err = -EINVAL; - break; - } - spin_unlock_irqrestore(&he_dev->global_lock, flags); - if (err == 0) - if (copy_to_user(arg, ®, - sizeof(struct he_ioctl_reg))) - return -EFAULT; - break; - default: -#ifdef CONFIG_ATM_HE_USE_SUNI - if (atm_dev->phy && atm_dev->phy->ioctl) - err = atm_dev->phy->ioctl(atm_dev, cmd, arg); -#else /* CONFIG_ATM_HE_USE_SUNI */ - err = -EINVAL; -#endif /* CONFIG_ATM_HE_USE_SUNI */ - break; - } - - return err; -} - -static void -he_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - - HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); - - spin_lock_irqsave(&he_dev->global_lock, flags); - he_writel(he_dev, val, FRAMER + (addr*4)); - (void) he_readl(he_dev, FRAMER + (addr*4)); /* flush posted writes */ - spin_unlock_irqrestore(&he_dev->global_lock, flags); -} - - -static unsigned char -he_phy_get(struct atm_dev *atm_dev, unsigned long addr) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(atm_dev); - unsigned reg; - - spin_lock_irqsave(&he_dev->global_lock, flags); - reg = he_readl(he_dev, FRAMER + (addr*4)); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); - return reg; -} - -static int -he_proc_read(struct atm_dev *dev, loff_t *pos, char *page) -{ - unsigned long flags; - struct he_dev *he_dev = HE_DEV(dev); - int left, i; -#ifdef notdef - struct he_rbrq *rbrq_tail; - struct he_tpdrq *tpdrq_head; - int rbpl_head, rbpl_tail; -#endif - static long mcc = 0, oec = 0, dcc = 0, cec = 0; - - - left = *pos; - if (!left--) - return sprintf(page, "ATM he driver\n"); - - if (!left--) - return sprintf(page, "%s%s\n\n", - he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM"); - - if (!left--) - return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); - - spin_lock_irqsave(&he_dev->global_lock, flags); - mcc += he_readl(he_dev, MCC); - oec += he_readl(he_dev, OEC); - dcc += he_readl(he_dev, DCC); - cec += he_readl(he_dev, CEC); - spin_unlock_irqrestore(&he_dev->global_lock, flags); - - if (!left--) - return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", - mcc, oec, dcc, cec); - - if (!left--) - return sprintf(page, "irq_size = %d inuse = ? peak = %d\n", - CONFIG_IRQ_SIZE, he_dev->irq_peak); - - if (!left--) - return sprintf(page, "tpdrq_size = %d inuse = ?\n", - CONFIG_TPDRQ_SIZE); - - if (!left--) - return sprintf(page, "rbrq_size = %d inuse = ? peak = %d\n", - CONFIG_RBRQ_SIZE, he_dev->rbrq_peak); - - if (!left--) - return sprintf(page, "tbrq_size = %d peak = %d\n", - CONFIG_TBRQ_SIZE, he_dev->tbrq_peak); - - -#ifdef notdef - rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); - rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); - - inuse = rbpl_head - rbpl_tail; - if (inuse < 0) - inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); - inuse /= sizeof(struct he_rbp); - - if (!left--) - return sprintf(page, "rbpl_size = %d inuse = %d\n\n", - CONFIG_RBPL_SIZE, inuse); -#endif - - if (!left--) - return sprintf(page, "rate controller periods (cbr)\n pcr #vc\n"); - - for (i = 0; i < HE_NUM_CS_STPER; ++i) - if (!left--) - return sprintf(page, "cs_stper%-2d %8ld %3d\n", i, - he_dev->cs_stper[i].pcr, - he_dev->cs_stper[i].inuse); - - if (!left--) - return sprintf(page, "total bw (cbr): %d (limit %d)\n", - he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9); - - return 0; -} - -/* eeprom routines -- see 4.7 */ - -static u8 read_prom_byte(struct he_dev *he_dev, int addr) -{ - u32 val = 0, tmp_read = 0; - int i, j = 0; - u8 byte_read = 0; - - val = readl(he_dev->membase + HOST_CNTL); - val &= 0xFFFFE0FF; - - /* Turn on write enable */ - val |= 0x800; - he_writel(he_dev, val, HOST_CNTL); - - /* Send READ instruction */ - for (i = 0; i < ARRAY_SIZE(readtab); i++) { - he_writel(he_dev, val | readtab[i], HOST_CNTL); - udelay(EEPROM_DELAY); - } - - /* Next, we need to send the byte address to read from */ - for (i = 7; i >= 0; i--) { - he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); - udelay(EEPROM_DELAY); - he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); - udelay(EEPROM_DELAY); - } - - j = 0; - - val &= 0xFFFFF7FF; /* Turn off write enable */ - he_writel(he_dev, val, HOST_CNTL); - - /* Now, we can read data from the EEPROM by clocking it in */ - for (i = 7; i >= 0; i--) { - he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - tmp_read = he_readl(he_dev, HOST_CNTL); - byte_read |= (unsigned char) - ((tmp_read & ID_DOUT) >> ID_DOFFSET << i); - he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - } - - he_writel(he_dev, val | ID_CS, HOST_CNTL); - udelay(EEPROM_DELAY); - - return byte_read; -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("chas williams "); -MODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver"); -module_param(disable64, bool, 0); -MODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers"); -module_param(nvpibits, short, 0); -MODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)"); -module_param(nvcibits, short, 0); -MODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)"); -module_param(rx_skb_reserve, short, 0); -MODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)"); -module_param(irq_coalesce, bool, 0); -MODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)"); -module_param(sdh, bool, 0); -MODULE_PARM_DESC(sdh, "use SDH framing (default 0)"); - -static const struct pci_device_id he_pci_tbl[] = { - { PCI_VDEVICE(FORE, PCI_DEVICE_ID_FORE_HE), 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, he_pci_tbl); - -static struct pci_driver he_driver = { - .name = "he", - .probe = he_init_one, - .remove = he_remove_one, - .id_table = he_pci_tbl, -}; - -module_pci_driver(he_driver); diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c deleted file mode 100644 index 4bbcca7f77c8..000000000000 --- a/drivers/atm/idt77105.c +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* drivers/atm/idt77105.c - IDT77105 (PHY) driver */ - -/* Written 1999 by Greg Banks, NEC Australia . Based on suni.c */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "idt77105.h" - -#undef GENERAL_DEBUG - -#ifdef GENERAL_DEBUG -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - - -struct idt77105_priv { - struct idt77105_stats stats; /* link diagnostics */ - struct atm_dev *dev; /* device back-pointer */ - struct idt77105_priv *next; - int loop_mode; - unsigned char old_mcr; /* storage of MCR reg while signal lost */ -}; - -static DEFINE_SPINLOCK(idt77105_priv_lock); - -#define PRIV(dev) ((struct idt77105_priv *) dev->phy_data) - -#define PUT(val,reg) dev->ops->phy_put(dev,val,IDT77105_##reg) -#define GET(reg) dev->ops->phy_get(dev,IDT77105_##reg) - -static void idt77105_stats_timer_func(struct timer_list *); -static void idt77105_restart_timer_func(struct timer_list *); - - -static DEFINE_TIMER(stats_timer, idt77105_stats_timer_func); -static DEFINE_TIMER(restart_timer, idt77105_restart_timer_func); -static int start_timer = 1; -static struct idt77105_priv *idt77105_all = NULL; - -/* - * Retrieve the value of one of the IDT77105's counters. - * `counter' is one of the IDT77105_CTRSEL_* constants. - */ -static u16 get_counter(struct atm_dev *dev, int counter) -{ - u16 val; - - /* write the counter bit into PHY register 6 */ - PUT(counter, CTRSEL); - /* read the low 8 bits from register 4 */ - val = GET(CTRLO); - /* read the high 8 bits from register 5 */ - val |= GET(CTRHI)<<8; - - return val; -} - -/* - * Timer function called every second to gather statistics - * from the 77105. This is done because the h/w registers - * will overflow if not read at least once per second. The - * kernel's stats are much higher precision. Also, having - * a separate copy of the stats allows implementation of - * an ioctl which gathers the stats *without* zero'ing them. - */ -static void idt77105_stats_timer_func(struct timer_list *unused) -{ - struct idt77105_priv *walk; - struct atm_dev *dev; - struct idt77105_stats *stats; - - DPRINTK("IDT77105 gathering statistics\n"); - for (walk = idt77105_all; walk; walk = walk->next) { - dev = walk->dev; - - stats = &walk->stats; - stats->symbol_errors += get_counter(dev, IDT77105_CTRSEL_SEC); - stats->tx_cells += get_counter(dev, IDT77105_CTRSEL_TCC); - stats->rx_cells += get_counter(dev, IDT77105_CTRSEL_RCC); - stats->rx_hec_errors += get_counter(dev, IDT77105_CTRSEL_RHEC); - } - if (!start_timer) mod_timer(&stats_timer,jiffies+IDT77105_STATS_TIMER_PERIOD); -} - - -/* - * A separate timer func which handles restarting PHY chips which - * have had the cable re-inserted after being pulled out. This is - * done by polling the Good Signal Bit in the Interrupt Status - * register every 5 seconds. The other technique (checking Good - * Signal Bit in the interrupt handler) cannot be used because PHY - * interrupts need to be disabled when the cable is pulled out - * to avoid lots of spurious cell error interrupts. - */ -static void idt77105_restart_timer_func(struct timer_list *unused) -{ - struct idt77105_priv *walk; - struct atm_dev *dev; - unsigned char istat; - - DPRINTK("IDT77105 checking for cable re-insertion\n"); - for (walk = idt77105_all; walk; walk = walk->next) { - dev = walk->dev; - - if (dev->signal != ATM_PHY_SIG_LOST) - continue; - - istat = GET(ISTAT); /* side effect: clears all interrupt status bits */ - if (istat & IDT77105_ISTAT_GOODSIG) { - /* Found signal again */ - atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND); - printk(KERN_NOTICE "%s(itf %d): signal detected again\n", - dev->type,dev->number); - /* flush the receive FIFO */ - PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG); - /* re-enable interrupts */ - PUT( walk->old_mcr ,MCR); - } - } - if (!start_timer) mod_timer(&restart_timer,jiffies+IDT77105_RESTART_TIMER_PERIOD); -} - - -static int fetch_stats(struct atm_dev *dev,struct idt77105_stats __user *arg,int zero) -{ - unsigned long flags; - struct idt77105_stats stats; - - spin_lock_irqsave(&idt77105_priv_lock, flags); - memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats)); - if (zero) - memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats)); - spin_unlock_irqrestore(&idt77105_priv_lock, flags); - if (arg == NULL) - return 0; - return copy_to_user(arg, &stats, - sizeof(struct idt77105_stats)) ? -EFAULT : 0; -} - - -static int set_loopback(struct atm_dev *dev,int mode) -{ - int diag; - - diag = GET(DIAG) & ~IDT77105_DIAG_LCMASK; - switch (mode) { - case ATM_LM_NONE: - break; - case ATM_LM_LOC_ATM: - diag |= IDT77105_DIAG_LC_PHY_LOOPBACK; - break; - case ATM_LM_RMT_ATM: - diag |= IDT77105_DIAG_LC_LINE_LOOPBACK; - break; - default: - return -EINVAL; - } - PUT(diag,DIAG); - printk(KERN_NOTICE "%s(%d) Loopback mode is: %s\n", dev->type, - dev->number, - (mode == ATM_LM_NONE ? "NONE" : - (mode == ATM_LM_LOC_ATM ? "DIAG (local)" : - (mode == IDT77105_DIAG_LC_LINE_LOOPBACK ? "LOOP (remote)" : - "unknown"))) - ); - PRIV(dev)->loop_mode = mode; - return 0; -} - - -static int idt77105_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - printk(KERN_NOTICE "%s(%d) idt77105_ioctl() called\n",dev->type,dev->number); - switch (cmd) { - case IDT77105_GETSTATZ: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - fallthrough; - case IDT77105_GETSTAT: - return fetch_stats(dev, arg, cmd == IDT77105_GETSTATZ); - case ATM_SETLOOP: - return set_loopback(dev,(int)(unsigned long) arg); - case ATM_GETLOOP: - return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? - -EFAULT : 0; - case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_ATM | ATM_LM_RMT_ATM, - (int __user *) arg) ? -EFAULT : 0; - default: - return -ENOIOCTLCMD; - } -} - - - -static void idt77105_int(struct atm_dev *dev) -{ - unsigned char istat; - - istat = GET(ISTAT); /* side effect: clears all interrupt status bits */ - - DPRINTK("IDT77105 generated an interrupt, istat=%02x\n", (unsigned)istat); - - if (istat & IDT77105_ISTAT_RSCC) { - /* Rx Signal Condition Change - line went up or down */ - if (istat & IDT77105_ISTAT_GOODSIG) { /* signal detected again */ - /* This should not happen (restart timer does it) but JIC */ - atm_dev_signal_change(dev, ATM_PHY_SIG_FOUND); - } else { /* signal lost */ - /* - * Disable interrupts and stop all transmission and - * reception - the restart timer will restore these. - */ - PRIV(dev)->old_mcr = GET(MCR); - PUT( - (PRIV(dev)->old_mcr| - IDT77105_MCR_DREC| - IDT77105_MCR_DRIC| - IDT77105_MCR_HALTTX - ) & ~IDT77105_MCR_EIP, MCR); - atm_dev_signal_change(dev, ATM_PHY_SIG_LOST); - printk(KERN_NOTICE "%s(itf %d): signal lost\n", - dev->type,dev->number); - } - } - - if (istat & IDT77105_ISTAT_RFO) { - /* Rx FIFO Overrun -- perform a FIFO flush */ - PUT( GET(DIAG) | IDT77105_DIAG_RFLUSH, DIAG); - printk(KERN_NOTICE "%s(itf %d): receive FIFO overrun\n", - dev->type,dev->number); - } -#ifdef GENERAL_DEBUG - if (istat & (IDT77105_ISTAT_HECERR | IDT77105_ISTAT_SCR | - IDT77105_ISTAT_RSE)) { - /* normally don't care - just report in stats */ - printk(KERN_NOTICE "%s(itf %d): received cell with error\n", - dev->type,dev->number); - } -#endif -} - - -static int idt77105_start(struct atm_dev *dev) -{ - unsigned long flags; - - if (!(dev->phy_data = kmalloc_obj(struct idt77105_priv))) - return -ENOMEM; - PRIV(dev)->dev = dev; - spin_lock_irqsave(&idt77105_priv_lock, flags); - PRIV(dev)->next = idt77105_all; - idt77105_all = PRIV(dev); - spin_unlock_irqrestore(&idt77105_priv_lock, flags); - memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats)); - - /* initialise dev->signal from Good Signal Bit */ - atm_dev_signal_change(dev, - GET(ISTAT) & IDT77105_ISTAT_GOODSIG ? - ATM_PHY_SIG_FOUND : ATM_PHY_SIG_LOST); - if (dev->signal == ATM_PHY_SIG_LOST) - printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type, - dev->number); - - /* initialise loop mode from hardware */ - switch ( GET(DIAG) & IDT77105_DIAG_LCMASK ) { - case IDT77105_DIAG_LC_NORMAL: - PRIV(dev)->loop_mode = ATM_LM_NONE; - break; - case IDT77105_DIAG_LC_PHY_LOOPBACK: - PRIV(dev)->loop_mode = ATM_LM_LOC_ATM; - break; - case IDT77105_DIAG_LC_LINE_LOOPBACK: - PRIV(dev)->loop_mode = ATM_LM_RMT_ATM; - break; - } - - /* enable interrupts, e.g. on loss of signal */ - PRIV(dev)->old_mcr = GET(MCR); - if (dev->signal == ATM_PHY_SIG_FOUND) { - PRIV(dev)->old_mcr |= IDT77105_MCR_EIP; - PUT(PRIV(dev)->old_mcr, MCR); - } - - - idt77105_stats_timer_func(0); /* clear 77105 counters */ - (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ - - spin_lock_irqsave(&idt77105_priv_lock, flags); - if (start_timer) { - start_timer = 0; - - stats_timer.expires = jiffies+IDT77105_STATS_TIMER_PERIOD; - add_timer(&stats_timer); - - restart_timer.expires = jiffies+IDT77105_RESTART_TIMER_PERIOD; - add_timer(&restart_timer); - } - spin_unlock_irqrestore(&idt77105_priv_lock, flags); - return 0; -} - - -static int idt77105_stop(struct atm_dev *dev) -{ - struct idt77105_priv *walk, *prev; - - DPRINTK("%s(itf %d): stopping IDT77105\n",dev->type,dev->number); - - /* disable interrupts */ - PUT( GET(MCR) & ~IDT77105_MCR_EIP, MCR ); - - /* detach private struct from atm_dev & free */ - for (prev = NULL, walk = idt77105_all ; - walk != NULL; - prev = walk, walk = walk->next) { - if (walk->dev == dev) { - if (prev != NULL) - prev->next = walk->next; - else - idt77105_all = walk->next; - dev->phy = NULL; - dev->phy_data = NULL; - kfree(walk); - break; - } - } - - return 0; -} - - -static const struct atmphy_ops idt77105_ops = { - .start = idt77105_start, - .ioctl = idt77105_ioctl, - .interrupt = idt77105_int, - .stop = idt77105_stop, -}; - - -int idt77105_init(struct atm_dev *dev) -{ - dev->phy = &idt77105_ops; - return 0; -} - -EXPORT_SYMBOL(idt77105_init); - -static void __exit idt77105_exit(void) -{ - /* turn off timers */ - timer_delete_sync(&stats_timer); - timer_delete_sync(&restart_timer); -} - -module_exit(idt77105_exit); - -MODULE_DESCRIPTION("IDT77105 PHY driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c deleted file mode 100644 index 7f8aaf5e6e43..000000000000 --- a/drivers/atm/idt77252.c +++ /dev/null @@ -1,3797 +0,0 @@ -/******************************************************************* - * - * Copyright (c) 2000 ATecoM GmbH - * - * The author may be reached at ecd@atecom.com. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_ATM_IDT77252_USE_SUNI -#include "suni.h" -#endif /* CONFIG_ATM_IDT77252_USE_SUNI */ - - -#include "idt77252.h" -#include "idt77252_tables.h" - -static unsigned int vpibits = 1; - - -#define ATM_IDT77252_SEND_IDLE 1 - - -/* - * Debug HACKs. - */ -#define DEBUG_MODULE 1 -#undef HAVE_EEPROM /* does not work, yet. */ - -#ifdef CONFIG_ATM_IDT77252_DEBUG -static unsigned long debug = DBG_GENERAL; -#endif - - -#define SAR_RX_DELAY (SAR_CFG_RXINT_NODELAY) - - -/* - * SCQ Handling. - */ -static struct scq_info *alloc_scq(struct idt77252_dev *, int); -static void free_scq(struct idt77252_dev *, struct scq_info *); -static int queue_skb(struct idt77252_dev *, struct vc_map *, - struct sk_buff *, int oam); -static void drain_scq(struct idt77252_dev *, struct vc_map *); -static unsigned long get_free_scd(struct idt77252_dev *, struct vc_map *); -static void fill_scd(struct idt77252_dev *, struct scq_info *, int); - -/* - * FBQ Handling. - */ -static int push_rx_skb(struct idt77252_dev *, - struct sk_buff *, int queue); -static void recycle_rx_skb(struct idt77252_dev *, struct sk_buff *); -static void flush_rx_pool(struct idt77252_dev *, struct rx_pool *); -static void recycle_rx_pool_skb(struct idt77252_dev *, - struct rx_pool *); -static void add_rx_skb(struct idt77252_dev *, int queue, - unsigned int size, unsigned int count); - -/* - * RSQ Handling. - */ -static int init_rsq(struct idt77252_dev *); -static void deinit_rsq(struct idt77252_dev *); -static void idt77252_rx(struct idt77252_dev *); - -/* - * TSQ handling. - */ -static int init_tsq(struct idt77252_dev *); -static void deinit_tsq(struct idt77252_dev *); -static void idt77252_tx(struct idt77252_dev *); - - -/* - * ATM Interface. - */ -static void idt77252_dev_close(struct atm_dev *dev); -static int idt77252_open(struct atm_vcc *vcc); -static void idt77252_close(struct atm_vcc *vcc); -static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int idt77252_send_oam(struct atm_vcc *vcc, void *cell, - int flags); -static void idt77252_phy_put(struct atm_dev *dev, unsigned char value, - unsigned long addr); -static unsigned char idt77252_phy_get(struct atm_dev *dev, unsigned long addr); -static int idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, - int flags); -static int idt77252_proc_read(struct atm_dev *dev, loff_t * pos, - char *page); -static void idt77252_softint(struct work_struct *work); - - -static const struct atmdev_ops idt77252_ops = -{ - .dev_close = idt77252_dev_close, - .open = idt77252_open, - .close = idt77252_close, - .send = idt77252_send, - .send_oam = idt77252_send_oam, - .phy_put = idt77252_phy_put, - .phy_get = idt77252_phy_get, - .change_qos = idt77252_change_qos, - .proc_read = idt77252_proc_read, - .owner = THIS_MODULE -}; - -static struct idt77252_dev *idt77252_chain = NULL; -static unsigned int idt77252_sram_write_errors = 0; - -/*****************************************************************************/ -/* */ -/* I/O and Utility Bus */ -/* */ -/*****************************************************************************/ - -static void -waitfor_idle(struct idt77252_dev *card) -{ - u32 stat; - - stat = readl(SAR_REG_STAT); - while (stat & SAR_STAT_CMDBZ) - stat = readl(SAR_REG_STAT); -} - -static u32 -read_sram(struct idt77252_dev *card, unsigned long addr) -{ - unsigned long flags; - u32 value; - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_READ_SRAM | (addr << 2), SAR_REG_CMD); - waitfor_idle(card); - value = readl(SAR_REG_DR0); - spin_unlock_irqrestore(&card->cmd_lock, flags); - return value; -} - -static void -write_sram(struct idt77252_dev *card, unsigned long addr, u32 value) -{ - unsigned long flags; - - if ((idt77252_sram_write_errors == 0) && - (((addr > card->tst[0] + card->tst_size - 2) && - (addr < card->tst[0] + card->tst_size)) || - ((addr > card->tst[1] + card->tst_size - 2) && - (addr < card->tst[1] + card->tst_size)))) { - printk("%s: ERROR: TST JMP section at %08lx written: %08x\n", - card->name, addr, value); - } - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(value, SAR_REG_DR0); - writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); -} - -static u8 -read_utility(void *dev, unsigned long ubus_addr) -{ - struct idt77252_dev *card = dev; - unsigned long flags; - u8 value; - - if (!card) { - printk("Error: No such device.\n"); - return -1; - } - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_READ_UTILITY + ubus_addr, SAR_REG_CMD); - waitfor_idle(card); - value = readl(SAR_REG_DR0); - spin_unlock_irqrestore(&card->cmd_lock, flags); - return value; -} - -static void -write_utility(void *dev, unsigned long ubus_addr, u8 value) -{ - struct idt77252_dev *card = dev; - unsigned long flags; - - if (!card) { - printk("Error: No such device.\n"); - return; - } - - spin_lock_irqsave(&card->cmd_lock, flags); - writel((u32) value, SAR_REG_DR0); - writel(SAR_CMD_WRITE_UTILITY + ubus_addr, SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); -} - -#ifdef HAVE_EEPROM -static u32 rdsrtab[] = -{ - SAR_GP_EECS | SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ - 0, - SAR_GP_EESCLK, /* 0 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ -}; - -static u32 wrentab[] = -{ - SAR_GP_EECS | SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK /* 0 */ -}; - -static u32 rdtab[] = -{ - SAR_GP_EECS | SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO /* 1 */ -}; - -static u32 wrtab[] = -{ - SAR_GP_EECS | SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - 0, - SAR_GP_EESCLK, /* 0 */ - SAR_GP_EEDO, - SAR_GP_EESCLK | SAR_GP_EEDO, /* 1 */ - 0, - SAR_GP_EESCLK /* 0 */ -}; - -static u32 clktab[] = -{ - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0, - SAR_GP_EESCLK, - 0 -}; - -static u32 -idt77252_read_gp(struct idt77252_dev *card) -{ - u32 gp; - - gp = readl(SAR_REG_GP); -#if 0 - printk("RD: %s\n", gp & SAR_GP_EEDI ? "1" : "0"); -#endif - return gp; -} - -static void -idt77252_write_gp(struct idt77252_dev *card, u32 value) -{ - unsigned long flags; - -#if 0 - printk("WR: %s %s %s\n", value & SAR_GP_EECS ? " " : "/CS", - value & SAR_GP_EESCLK ? "HIGH" : "LOW ", - value & SAR_GP_EEDO ? "1" : "0"); -#endif - - spin_lock_irqsave(&card->cmd_lock, flags); - waitfor_idle(card); - writel(value, SAR_REG_GP); - spin_unlock_irqrestore(&card->cmd_lock, flags); -} - -static u8 -idt77252_eeprom_read_status(struct idt77252_dev *card) -{ - u8 byte; - u32 gp; - int i, j; - - gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - - for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { - idt77252_write_gp(card, gp | rdsrtab[i]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - byte = 0; - for (i = 0, j = 0; i < 8; i++) { - byte <<= 1; - - idt77252_write_gp(card, gp | clktab[j++]); - udelay(5); - - byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; - - idt77252_write_gp(card, gp | clktab[j++]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - return byte; -} - -static u8 -idt77252_eeprom_read_byte(struct idt77252_dev *card, u8 offset) -{ - u8 byte; - u32 gp; - int i, j; - - gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - - for (i = 0; i < ARRAY_SIZE(rdtab); i++) { - idt77252_write_gp(card, gp | rdtab[i]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - for (i = 0, j = 0; i < 8; i++) { - idt77252_write_gp(card, gp | clktab[j++] | - (offset & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - idt77252_write_gp(card, gp | clktab[j++] | - (offset & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - offset >>= 1; - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - byte = 0; - for (i = 0, j = 0; i < 8; i++) { - byte <<= 1; - - idt77252_write_gp(card, gp | clktab[j++]); - udelay(5); - - byte |= idt77252_read_gp(card) & SAR_GP_EEDI ? 1 : 0; - - idt77252_write_gp(card, gp | clktab[j++]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - return byte; -} - -static void -idt77252_eeprom_write_byte(struct idt77252_dev *card, u8 offset, u8 data) -{ - u32 gp; - int i, j; - - gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - - for (i = 0; i < ARRAY_SIZE(wrentab); i++) { - idt77252_write_gp(card, gp | wrentab[i]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - for (i = 0; i < ARRAY_SIZE(wrtab); i++) { - idt77252_write_gp(card, gp | wrtab[i]); - udelay(5); - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - for (i = 0, j = 0; i < 8; i++) { - idt77252_write_gp(card, gp | clktab[j++] | - (offset & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - idt77252_write_gp(card, gp | clktab[j++] | - (offset & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - offset >>= 1; - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - - for (i = 0, j = 0; i < 8; i++) { - idt77252_write_gp(card, gp | clktab[j++] | - (data & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - idt77252_write_gp(card, gp | clktab[j++] | - (data & 1 ? SAR_GP_EEDO : 0)); - udelay(5); - - data >>= 1; - } - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); -} - -static void -idt77252_eeprom_init(struct idt77252_dev *card) -{ - u32 gp; - - gp = idt77252_read_gp(card) & ~(SAR_GP_EESCLK|SAR_GP_EECS|SAR_GP_EEDO); - - idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); - udelay(5); - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); - idt77252_write_gp(card, gp | SAR_GP_EECS | SAR_GP_EESCLK); - udelay(5); - idt77252_write_gp(card, gp | SAR_GP_EECS); - udelay(5); -} -#endif /* HAVE_EEPROM */ - - -#ifdef CONFIG_ATM_IDT77252_DEBUG -static void -dump_tct(struct idt77252_dev *card, int index) -{ - unsigned long tct; - int i; - - tct = (unsigned long) (card->tct_base + index * SAR_SRAM_TCT_SIZE); - - printk("%s: TCT %x:", card->name, index); - for (i = 0; i < 8; i++) { - printk(" %08x", read_sram(card, tct + i)); - } - printk("\n"); -} - -static void -idt77252_tx_dump(struct idt77252_dev *card) -{ - struct atm_vcc *vcc; - struct vc_map *vc; - int i; - - printk("%s\n", __func__); - for (i = 0; i < card->tct_size; i++) { - vc = card->vcs[i]; - if (!vc) - continue; - - vcc = NULL; - if (vc->rx_vcc) - vcc = vc->rx_vcc; - else if (vc->tx_vcc) - vcc = vc->tx_vcc; - - if (!vcc) - continue; - - printk("%s: Connection %d:\n", card->name, vc->index); - dump_tct(card, vc->index); - } -} -#endif - - -/*****************************************************************************/ -/* */ -/* SCQ Handling */ -/* */ -/*****************************************************************************/ - -static int -sb_pool_add(struct idt77252_dev *card, struct sk_buff *skb, int queue) -{ - struct sb_pool *pool = &card->sbpool[queue]; - int index; - - index = pool->index; - while (pool->skb[index]) { - index = (index + 1) & FBQ_MASK; - if (index == pool->index) - return -ENOBUFS; - } - - pool->skb[index] = skb; - IDT77252_PRV_POOL(skb) = POOL_HANDLE(queue, index); - - pool->index = (index + 1) & FBQ_MASK; - return 0; -} - -static void -sb_pool_remove(struct idt77252_dev *card, struct sk_buff *skb) -{ - unsigned int queue, index; - u32 handle; - - handle = IDT77252_PRV_POOL(skb); - - queue = POOL_QUEUE(handle); - if (queue > 3) - return; - - index = POOL_INDEX(handle); - if (index > FBQ_SIZE - 1) - return; - - card->sbpool[queue].skb[index] = NULL; -} - -static struct sk_buff * -sb_pool_skb(struct idt77252_dev *card, u32 handle) -{ - unsigned int queue, index; - - queue = POOL_QUEUE(handle); - if (queue > 3) - return NULL; - - index = POOL_INDEX(handle); - if (index > FBQ_SIZE - 1) - return NULL; - - return card->sbpool[queue].skb[index]; -} - -static struct scq_info * -alloc_scq(struct idt77252_dev *card, int class) -{ - struct scq_info *scq; - - scq = kzalloc_obj(struct scq_info); - if (!scq) - return NULL; - scq->base = dma_alloc_coherent(&card->pcidev->dev, SCQ_SIZE, - &scq->paddr, GFP_KERNEL); - if (scq->base == NULL) { - kfree(scq); - return NULL; - } - - scq->next = scq->base; - scq->last = scq->base + (SCQ_ENTRIES - 1); - atomic_set(&scq->used, 0); - - spin_lock_init(&scq->lock); - spin_lock_init(&scq->skblock); - - skb_queue_head_init(&scq->transmit); - skb_queue_head_init(&scq->pending); - - TXPRINTK("idt77252: SCQ: base 0x%p, next 0x%p, last 0x%p, paddr %08llx\n", - scq->base, scq->next, scq->last, (unsigned long long)scq->paddr); - - return scq; -} - -static void -free_scq(struct idt77252_dev *card, struct scq_info *scq) -{ - struct sk_buff *skb; - struct atm_vcc *vcc; - - dma_free_coherent(&card->pcidev->dev, SCQ_SIZE, - scq->base, scq->paddr); - - while ((skb = skb_dequeue(&scq->transmit))) { - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb->len, DMA_TO_DEVICE); - - vcc = ATM_SKB(skb)->vcc; - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - } - - while ((skb = skb_dequeue(&scq->pending))) { - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb->len, DMA_TO_DEVICE); - - vcc = ATM_SKB(skb)->vcc; - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - } - - kfree(scq); -} - - -static int -push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb) -{ - struct scq_info *scq = vc->scq; - unsigned long flags; - struct scqe *tbd; - int entries; - - TXPRINTK("%s: SCQ: next 0x%p\n", card->name, scq->next); - - atomic_inc(&scq->used); - entries = atomic_read(&scq->used); - if (entries > (SCQ_ENTRIES - 1)) { - atomic_dec(&scq->used); - goto out; - } - - skb_queue_tail(&scq->transmit, skb); - - spin_lock_irqsave(&vc->lock, flags); - if (vc->estimator) { - struct atm_vcc *vcc = vc->tx_vcc; - struct sock *sk = sk_atm(vcc); - - vc->estimator->cells += (skb->len + 47) / 48; - if (refcount_read(&sk->sk_wmem_alloc) > - (sk->sk_sndbuf >> 1)) { - u32 cps = vc->estimator->maxcps; - - vc->estimator->cps = cps; - vc->estimator->avcps = cps << 5; - if (vc->lacr < vc->init_er) { - vc->lacr = vc->init_er; - writel(TCMDQ_LACR | (vc->lacr << 16) | - vc->index, SAR_REG_TCMDQ); - } - } - } - spin_unlock_irqrestore(&vc->lock, flags); - - tbd = &IDT77252_PRV_TBD(skb); - - spin_lock_irqsave(&scq->lock, flags); - scq->next->word_1 = cpu_to_le32(tbd->word_1 | - SAR_TBD_TSIF | SAR_TBD_GTSI); - scq->next->word_2 = cpu_to_le32(tbd->word_2); - scq->next->word_3 = cpu_to_le32(tbd->word_3); - scq->next->word_4 = cpu_to_le32(tbd->word_4); - - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - - write_sram(card, scq->scd, - scq->paddr + - (u32)((unsigned long)scq->next - (unsigned long)scq->base)); - spin_unlock_irqrestore(&scq->lock, flags); - - scq->trans_start = jiffies; - - if (test_and_clear_bit(VCF_IDLE, &vc->flags)) { - writel(TCMDQ_START_LACR | (vc->lacr << 16) | vc->index, - SAR_REG_TCMDQ); - } - - TXPRINTK("%d entries in SCQ used (push).\n", atomic_read(&scq->used)); - - XPRINTK("%s: SCQ (after push %2d) head = 0x%x, next = 0x%p.\n", - card->name, atomic_read(&scq->used), - read_sram(card, scq->scd + 1), scq->next); - - return 0; - -out: - if (time_after(jiffies, scq->trans_start + HZ)) { - printk("%s: Error pushing TBD for %d.%d\n", - card->name, vc->tx_vcc->vpi, vc->tx_vcc->vci); -#ifdef CONFIG_ATM_IDT77252_DEBUG - idt77252_tx_dump(card); -#endif - scq->trans_start = jiffies; - } - - return -ENOBUFS; -} - - -static void -drain_scq(struct idt77252_dev *card, struct vc_map *vc) -{ - struct scq_info *scq = vc->scq; - struct sk_buff *skb; - struct atm_vcc *vcc; - - TXPRINTK("%s: SCQ (before drain %2d) next = 0x%p.\n", - card->name, atomic_read(&scq->used), scq->next); - - skb = skb_dequeue(&scq->transmit); - if (skb) { - TXPRINTK("%s: freeing skb at %p.\n", card->name, skb); - - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb->len, DMA_TO_DEVICE); - - vcc = ATM_SKB(skb)->vcc; - - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb(skb); - - atomic_inc(&vcc->stats->tx); - } - - atomic_dec(&scq->used); - - spin_lock(&scq->skblock); - while ((skb = skb_dequeue(&scq->pending))) { - if (push_on_scq(card, vc, skb)) { - skb_queue_head(&vc->scq->pending, skb); - break; - } - } - spin_unlock(&scq->skblock); -} - -static int -queue_skb(struct idt77252_dev *card, struct vc_map *vc, - struct sk_buff *skb, int oam) -{ - struct atm_vcc *vcc; - struct scqe *tbd; - unsigned long flags; - int error; - int aal; - u32 word4; - - if (skb->len == 0) { - printk("%s: invalid skb->len (%d)\n", card->name, skb->len); - return -EINVAL; - } - - TXPRINTK("%s: Sending %d bytes of data.\n", - card->name, skb->len); - - tbd = &IDT77252_PRV_TBD(skb); - vcc = ATM_SKB(skb)->vcc; - word4 = (skb->data[0] << 24) | (skb->data[1] << 16) | - (skb->data[2] << 8) | (skb->data[3] << 0); - - IDT77252_PRV_PADDR(skb) = dma_map_single(&card->pcidev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (dma_mapping_error(&card->pcidev->dev, IDT77252_PRV_PADDR(skb))) - return -ENOMEM; - - error = -EINVAL; - - if (oam) { - if (skb->len != 52) - goto errout; - - tbd->word_1 = SAR_TBD_OAM | ATM_CELL_PAYLOAD | SAR_TBD_EPDU; - tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; - tbd->word_3 = 0x00000000; - tbd->word_4 = word4; - - if (test_bit(VCF_RSV, &vc->flags)) - vc = card->vcs[0]; - - goto done; - } - - if (test_bit(VCF_RSV, &vc->flags)) { - printk("%s: Trying to transmit on reserved VC\n", card->name); - goto errout; - } - - aal = vcc->qos.aal; - - switch (aal) { - case ATM_AAL0: - case ATM_AAL34: - if (skb->len > 52) - goto errout; - - if (aal == ATM_AAL0) - tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL0 | - ATM_CELL_PAYLOAD; - else - tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL34 | - ATM_CELL_PAYLOAD; - - tbd->word_2 = IDT77252_PRV_PADDR(skb) + 4; - tbd->word_3 = 0x00000000; - tbd->word_4 = word4; - break; - - case ATM_AAL5: - tbd->word_1 = SAR_TBD_EPDU | SAR_TBD_AAL5 | skb->len; - tbd->word_2 = IDT77252_PRV_PADDR(skb); - tbd->word_3 = skb->len; - tbd->word_4 = (vcc->vpi << SAR_TBD_VPI_SHIFT) | - (vcc->vci << SAR_TBD_VCI_SHIFT); - break; - - case ATM_AAL1: - case ATM_AAL2: - default: - printk("%s: Traffic type not supported.\n", card->name); - error = -EPROTONOSUPPORT; - goto errout; - } - -done: - spin_lock_irqsave(&vc->scq->skblock, flags); - skb_queue_tail(&vc->scq->pending, skb); - - while ((skb = skb_dequeue(&vc->scq->pending))) { - if (push_on_scq(card, vc, skb)) { - skb_queue_head(&vc->scq->pending, skb); - break; - } - } - spin_unlock_irqrestore(&vc->scq->skblock, flags); - - return 0; - -errout: - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb->len, DMA_TO_DEVICE); - return error; -} - -static unsigned long -get_free_scd(struct idt77252_dev *card, struct vc_map *vc) -{ - int i; - - for (i = 0; i < card->scd_size; i++) { - if (!card->scd2vc[i]) { - card->scd2vc[i] = vc; - vc->scd_index = i; - return card->scd_base + i * SAR_SRAM_SCD_SIZE; - } - } - return 0; -} - -static void -fill_scd(struct idt77252_dev *card, struct scq_info *scq, int class) -{ - write_sram(card, scq->scd, scq->paddr); - write_sram(card, scq->scd + 1, 0x00000000); - write_sram(card, scq->scd + 2, 0xffffffff); - write_sram(card, scq->scd + 3, 0x00000000); -} - -static void -clear_scd(struct idt77252_dev *card, struct scq_info *scq, int class) -{ - return; -} - -/*****************************************************************************/ -/* */ -/* RSQ Handling */ -/* */ -/*****************************************************************************/ - -static int -init_rsq(struct idt77252_dev *card) -{ - struct rsq_entry *rsqe; - - card->rsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE, - &card->rsq.paddr, GFP_KERNEL); - if (card->rsq.base == NULL) { - printk("%s: can't allocate RSQ.\n", card->name); - return -1; - } - - card->rsq.last = card->rsq.base + RSQ_NUM_ENTRIES - 1; - card->rsq.next = card->rsq.last; - for (rsqe = card->rsq.base; rsqe <= card->rsq.last; rsqe++) - rsqe->word_4 = 0; - - writel((unsigned long) card->rsq.last - (unsigned long) card->rsq.base, - SAR_REG_RSQH); - writel(card->rsq.paddr, SAR_REG_RSQB); - - IPRINTK("%s: RSQ base at 0x%lx (0x%x).\n", card->name, - (unsigned long) card->rsq.base, - readl(SAR_REG_RSQB)); - IPRINTK("%s: RSQ head = 0x%x, base = 0x%x, tail = 0x%x.\n", - card->name, - readl(SAR_REG_RSQH), - readl(SAR_REG_RSQB), - readl(SAR_REG_RSQT)); - - return 0; -} - -static void -deinit_rsq(struct idt77252_dev *card) -{ - dma_free_coherent(&card->pcidev->dev, RSQSIZE, - card->rsq.base, card->rsq.paddr); -} - -static void -dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe) -{ - struct atm_vcc *vcc; - struct sk_buff *skb; - struct rx_pool *rpp; - struct vc_map *vc; - u32 header, vpi, vci; - u32 stat; - int i; - - stat = le32_to_cpu(rsqe->word_4); - - if (stat & SAR_RSQE_IDLE) { - RXPRINTK("%s: message about inactive connection.\n", - card->name); - return; - } - - skb = sb_pool_skb(card, le32_to_cpu(rsqe->word_2)); - if (skb == NULL) { - printk("%s: NULL skb in %s, rsqe: %08x %08x %08x %08x\n", - card->name, __func__, - le32_to_cpu(rsqe->word_1), le32_to_cpu(rsqe->word_2), - le32_to_cpu(rsqe->word_3), le32_to_cpu(rsqe->word_4)); - return; - } - - header = le32_to_cpu(rsqe->word_1); - vpi = (header >> 16) & 0x00ff; - vci = (header >> 0) & 0xffff; - - RXPRINTK("%s: SDU for %d.%d received in buffer 0x%p (data 0x%p).\n", - card->name, vpi, vci, skb, skb->data); - - if ((vpi >= (1 << card->vpibits)) || (vci != (vci & card->vcimask))) { - printk("%s: SDU received for out-of-range vc %u.%u\n", - card->name, vpi, vci); - recycle_rx_skb(card, skb); - return; - } - - vc = card->vcs[VPCI2VC(card, vpi, vci)]; - if (!vc || !test_bit(VCF_RX, &vc->flags)) { - printk("%s: SDU received on non RX vc %u.%u\n", - card->name, vpi, vci); - recycle_rx_skb(card, skb); - return; - } - - vcc = vc->rx_vcc; - - dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - DMA_FROM_DEVICE); - - if ((vcc->qos.aal == ATM_AAL0) || - (vcc->qos.aal == ATM_AAL34)) { - struct sk_buff *sb; - unsigned char *cell; - u32 aal0; - - cell = skb->data; - for (i = (stat & SAR_RSQE_CELLCNT); i; i--) { - if ((sb = dev_alloc_skb(64)) == NULL) { - printk("%s: Can't allocate buffers for aal0.\n", - card->name); - atomic_add(i, &vcc->stats->rx_drop); - break; - } - if (!atm_charge(vcc, sb->truesize)) { - RXPRINTK("%s: atm_charge() dropped aal0 packets.\n", - card->name); - atomic_add(i - 1, &vcc->stats->rx_drop); - dev_kfree_skb(sb); - break; - } - aal0 = (vpi << ATM_HDR_VPI_SHIFT) | - (vci << ATM_HDR_VCI_SHIFT); - aal0 |= (stat & SAR_RSQE_EPDU) ? 0x00000002 : 0; - aal0 |= (stat & SAR_RSQE_CLP) ? 0x00000001 : 0; - - *((u32 *) sb->data) = aal0; - skb_put(sb, sizeof(u32)); - skb_put_data(sb, cell, ATM_CELL_PAYLOAD); - - ATM_SKB(sb)->vcc = vcc; - __net_timestamp(sb); - vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); - - cell += ATM_CELL_PAYLOAD; - } - - recycle_rx_skb(card, skb); - return; - } - if (vcc->qos.aal != ATM_AAL5) { - printk("%s: Unexpected AAL type in dequeue_rx(): %d.\n", - card->name, vcc->qos.aal); - recycle_rx_skb(card, skb); - return; - } - skb->len = (stat & SAR_RSQE_CELLCNT) * ATM_CELL_PAYLOAD; - - rpp = &vc->rcv.rx_pool; - - __skb_queue_tail(&rpp->queue, skb); - rpp->len += skb->len; - - if (stat & SAR_RSQE_EPDU) { - unsigned int len, truesize; - unsigned char *l1l2; - - l1l2 = (unsigned char *) ((unsigned long) skb->data + skb->len - 6); - - len = (l1l2[0] << 8) | l1l2[1]; - len = len ? len : 0x10000; - - RXPRINTK("%s: PDU has %d bytes.\n", card->name, len); - - if ((len + 8 > rpp->len) || (len + (47 + 8) < rpp->len)) { - RXPRINTK("%s: AAL5 PDU size mismatch: %d != %d. " - "(CDC: %08x)\n", - card->name, len, rpp->len, readl(SAR_REG_CDC)); - recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); - return; - } - if (stat & SAR_RSQE_CRC) { - RXPRINTK("%s: AAL5 CRC error.\n", card->name); - recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); - return; - } - if (skb_queue_len(&rpp->queue) > 1) { - struct sk_buff *sb; - - skb = dev_alloc_skb(rpp->len); - if (!skb) { - RXPRINTK("%s: Can't alloc RX skb.\n", - card->name); - recycle_rx_pool_skb(card, rpp); - atomic_inc(&vcc->stats->rx_err); - return; - } - if (!atm_charge(vcc, skb->truesize)) { - recycle_rx_pool_skb(card, rpp); - dev_kfree_skb(skb); - return; - } - skb_queue_walk(&rpp->queue, sb) - skb_put_data(skb, sb->data, sb->len); - - recycle_rx_pool_skb(card, rpp); - - skb_trim(skb, len); - ATM_SKB(skb)->vcc = vcc; - __net_timestamp(skb); - - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - - return; - } - - flush_rx_pool(card, rpp); - - if (!atm_charge(vcc, skb->truesize)) { - recycle_rx_skb(card, skb); - return; - } - - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - DMA_FROM_DEVICE); - sb_pool_remove(card, skb); - - skb_trim(skb, len); - ATM_SKB(skb)->vcc = vcc; - __net_timestamp(skb); - - truesize = skb->truesize; - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - - if (truesize > SAR_FB_SIZE_3) - add_rx_skb(card, 3, SAR_FB_SIZE_3, 1); - else if (truesize > SAR_FB_SIZE_2) - add_rx_skb(card, 2, SAR_FB_SIZE_2, 1); - else if (truesize > SAR_FB_SIZE_1) - add_rx_skb(card, 1, SAR_FB_SIZE_1, 1); - else - add_rx_skb(card, 0, SAR_FB_SIZE_0, 1); - return; - } -} - -static void -idt77252_rx(struct idt77252_dev *card) -{ - struct rsq_entry *rsqe; - - if (card->rsq.next == card->rsq.last) - rsqe = card->rsq.base; - else - rsqe = card->rsq.next + 1; - - if (!(le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID)) { - RXPRINTK("%s: no entry in RSQ.\n", card->name); - return; - } - - do { - dequeue_rx(card, rsqe); - rsqe->word_4 = 0; - card->rsq.next = rsqe; - if (card->rsq.next == card->rsq.last) - rsqe = card->rsq.base; - else - rsqe = card->rsq.next + 1; - } while (le32_to_cpu(rsqe->word_4) & SAR_RSQE_VALID); - - writel((unsigned long) card->rsq.next - (unsigned long) card->rsq.base, - SAR_REG_RSQH); -} - -static void -idt77252_rx_raw(struct idt77252_dev *card) -{ - struct sk_buff *queue; - u32 head, tail; - struct atm_vcc *vcc; - struct vc_map *vc; - struct sk_buff *sb; - - if (card->raw_cell_head == NULL) { - u32 handle = le32_to_cpu(*(card->raw_cell_hnd + 1)); - card->raw_cell_head = sb_pool_skb(card, handle); - } - - queue = card->raw_cell_head; - if (!queue) - return; - - head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16); - tail = readl(SAR_REG_RAWCT); - - dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(queue), - skb_end_offset(queue) - 16, - DMA_FROM_DEVICE); - - while (head != tail) { - unsigned int vpi, vci; - u32 header; - - header = le32_to_cpu(*(u32 *) &queue->data[0]); - - vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT; - vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT; - -#ifdef CONFIG_ATM_IDT77252_DEBUG - if (debug & DBG_RAW_CELL) { - int i; - - printk("%s: raw cell %x.%02x.%04x.%x.%x\n", - card->name, (header >> 28) & 0x000f, - (header >> 20) & 0x00ff, - (header >> 4) & 0xffff, - (header >> 1) & 0x0007, - (header >> 0) & 0x0001); - for (i = 16; i < 64; i++) - printk(" %02x", queue->data[i]); - printk("\n"); - } -#endif - - if (vpi >= (1<vpibits) || vci >= (1<vcibits)) { - RPRINTK("%s: SDU received for out-of-range vc %u.%u\n", - card->name, vpi, vci); - goto drop; - } - - vc = card->vcs[VPCI2VC(card, vpi, vci)]; - if (!vc || !test_bit(VCF_RX, &vc->flags)) { - RPRINTK("%s: SDU received on non RX vc %u.%u\n", - card->name, vpi, vci); - goto drop; - } - - vcc = vc->rx_vcc; - - if (vcc->qos.aal != ATM_AAL0) { - RPRINTK("%s: raw cell for non AAL0 vc %u.%u\n", - card->name, vpi, vci); - atomic_inc(&vcc->stats->rx_drop); - goto drop; - } - - if ((sb = dev_alloc_skb(64)) == NULL) { - printk("%s: Can't allocate buffers for AAL0.\n", - card->name); - atomic_inc(&vcc->stats->rx_err); - goto drop; - } - - if (!atm_charge(vcc, sb->truesize)) { - RXPRINTK("%s: atm_charge() dropped AAL0 packets.\n", - card->name); - dev_kfree_skb(sb); - goto drop; - } - - *((u32 *) sb->data) = header; - skb_put(sb, sizeof(u32)); - skb_put_data(sb, &(queue->data[16]), ATM_CELL_PAYLOAD); - - ATM_SKB(sb)->vcc = vcc; - __net_timestamp(sb); - vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); - -drop: - skb_pull(queue, 64); - - head = IDT77252_PRV_PADDR(queue) - + (queue->data - queue->head - 16); - - if (queue->len < 128) { - struct sk_buff *next; - u32 handle; - - head = le32_to_cpu(*(u32 *) &queue->data[0]); - handle = le32_to_cpu(*(u32 *) &queue->data[4]); - - next = sb_pool_skb(card, handle); - recycle_rx_skb(card, queue); - - if (next) { - card->raw_cell_head = next; - queue = card->raw_cell_head; - dma_sync_single_for_cpu(&card->pcidev->dev, - IDT77252_PRV_PADDR(queue), - (skb_end_pointer(queue) - - queue->data), - DMA_FROM_DEVICE); - } else { - card->raw_cell_head = NULL; - printk("%s: raw cell queue overrun\n", - card->name); - break; - } - } - } -} - - -/*****************************************************************************/ -/* */ -/* TSQ Handling */ -/* */ -/*****************************************************************************/ - -static int -init_tsq(struct idt77252_dev *card) -{ - struct tsq_entry *tsqe; - - card->tsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE, - &card->tsq.paddr, GFP_KERNEL); - if (card->tsq.base == NULL) { - printk("%s: can't allocate TSQ.\n", card->name); - return -1; - } - - card->tsq.last = card->tsq.base + TSQ_NUM_ENTRIES - 1; - card->tsq.next = card->tsq.last; - for (tsqe = card->tsq.base; tsqe <= card->tsq.last; tsqe++) - tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID); - - writel(card->tsq.paddr, SAR_REG_TSQB); - writel((unsigned long) card->tsq.next - (unsigned long) card->tsq.base, - SAR_REG_TSQH); - - return 0; -} - -static void -deinit_tsq(struct idt77252_dev *card) -{ - dma_free_coherent(&card->pcidev->dev, TSQSIZE, - card->tsq.base, card->tsq.paddr); -} - -static void -idt77252_tx(struct idt77252_dev *card) -{ - struct tsq_entry *tsqe; - unsigned int vpi, vci; - struct vc_map *vc; - u32 conn, stat; - - if (card->tsq.next == card->tsq.last) - tsqe = card->tsq.base; - else - tsqe = card->tsq.next + 1; - - TXPRINTK("idt77252_tx: tsq %p: base %p, next %p, last %p\n", tsqe, - card->tsq.base, card->tsq.next, card->tsq.last); - TXPRINTK("idt77252_tx: tsqb %08x, tsqt %08x, tsqh %08x, \n", - readl(SAR_REG_TSQB), - readl(SAR_REG_TSQT), - readl(SAR_REG_TSQH)); - - stat = le32_to_cpu(tsqe->word_2); - - if (stat & SAR_TSQE_INVALID) - return; - - do { - TXPRINTK("tsqe: 0x%p [0x%08x 0x%08x]\n", tsqe, - le32_to_cpu(tsqe->word_1), - le32_to_cpu(tsqe->word_2)); - - switch (stat & SAR_TSQE_TYPE) { - case SAR_TSQE_TYPE_TIMER: - TXPRINTK("%s: Timer RollOver detected.\n", card->name); - break; - - case SAR_TSQE_TYPE_IDLE: - - conn = le32_to_cpu(tsqe->word_1); - - if (SAR_TSQE_TAG(stat) == 0x10) { -#ifdef NOTDEF - printk("%s: Connection %d halted.\n", - card->name, - le32_to_cpu(tsqe->word_1) & 0x1fff); -#endif - break; - } - - vc = card->vcs[conn & 0x1fff]; - if (!vc) { - printk("%s: could not find VC from conn %d\n", - card->name, conn & 0x1fff); - break; - } - - printk("%s: Connection %d IDLE.\n", - card->name, vc->index); - - set_bit(VCF_IDLE, &vc->flags); - break; - - case SAR_TSQE_TYPE_TSR: - - conn = le32_to_cpu(tsqe->word_1); - - vc = card->vcs[conn & 0x1fff]; - if (!vc) { - printk("%s: no VC at index %d\n", - card->name, - le32_to_cpu(tsqe->word_1) & 0x1fff); - break; - } - - drain_scq(card, vc); - break; - - case SAR_TSQE_TYPE_TBD_COMP: - - conn = le32_to_cpu(tsqe->word_1); - - vpi = (conn >> SAR_TBD_VPI_SHIFT) & 0x00ff; - vci = (conn >> SAR_TBD_VCI_SHIFT) & 0xffff; - - if (vpi >= (1 << card->vpibits) || - vci >= (1 << card->vcibits)) { - printk("%s: TBD complete: " - "out of range VPI.VCI %u.%u\n", - card->name, vpi, vci); - break; - } - - vc = card->vcs[VPCI2VC(card, vpi, vci)]; - if (!vc) { - printk("%s: TBD complete: " - "no VC at VPI.VCI %u.%u\n", - card->name, vpi, vci); - break; - } - - drain_scq(card, vc); - break; - } - - tsqe->word_2 = cpu_to_le32(SAR_TSQE_INVALID); - - card->tsq.next = tsqe; - if (card->tsq.next == card->tsq.last) - tsqe = card->tsq.base; - else - tsqe = card->tsq.next + 1; - - TXPRINTK("tsqe: %p: base %p, next %p, last %p\n", tsqe, - card->tsq.base, card->tsq.next, card->tsq.last); - - stat = le32_to_cpu(tsqe->word_2); - - } while (!(stat & SAR_TSQE_INVALID)); - - writel((unsigned long)card->tsq.next - (unsigned long)card->tsq.base, - SAR_REG_TSQH); - - XPRINTK("idt77252_tx-after writel%d: TSQ head = 0x%x, tail = 0x%x, next = 0x%p.\n", - card->index, readl(SAR_REG_TSQH), - readl(SAR_REG_TSQT), card->tsq.next); -} - - -static void -tst_timer(struct timer_list *t) -{ - struct idt77252_dev *card = timer_container_of(card, t, tst_timer); - unsigned long base, idle, jump; - unsigned long flags; - u32 pc; - int e; - - spin_lock_irqsave(&card->tst_lock, flags); - - base = card->tst[card->tst_index]; - idle = card->tst[card->tst_index ^ 1]; - - if (test_bit(TST_SWITCH_WAIT, &card->tst_state)) { - jump = base + card->tst_size - 2; - - pc = readl(SAR_REG_NOW) >> 2; - if ((pc ^ idle) & ~(card->tst_size - 1)) { - mod_timer(&card->tst_timer, jiffies + 1); - goto out; - } - - clear_bit(TST_SWITCH_WAIT, &card->tst_state); - - card->tst_index ^= 1; - write_sram(card, jump, TSTE_OPC_JMP | (base << 2)); - - base = card->tst[card->tst_index]; - idle = card->tst[card->tst_index ^ 1]; - - for (e = 0; e < card->tst_size - 2; e++) { - if (card->soft_tst[e].tste & TSTE_PUSH_IDLE) { - write_sram(card, idle + e, - card->soft_tst[e].tste & TSTE_MASK); - card->soft_tst[e].tste &= ~(TSTE_PUSH_IDLE); - } - } - } - - if (test_and_clear_bit(TST_SWITCH_PENDING, &card->tst_state)) { - - for (e = 0; e < card->tst_size - 2; e++) { - if (card->soft_tst[e].tste & TSTE_PUSH_ACTIVE) { - write_sram(card, idle + e, - card->soft_tst[e].tste & TSTE_MASK); - card->soft_tst[e].tste &= ~(TSTE_PUSH_ACTIVE); - card->soft_tst[e].tste |= TSTE_PUSH_IDLE; - } - } - - jump = base + card->tst_size - 2; - - write_sram(card, jump, TSTE_OPC_NULL); - set_bit(TST_SWITCH_WAIT, &card->tst_state); - - mod_timer(&card->tst_timer, jiffies + 1); - } - -out: - spin_unlock_irqrestore(&card->tst_lock, flags); -} - -static int -__fill_tst(struct idt77252_dev *card, struct vc_map *vc, - int n, unsigned int opc) -{ - unsigned long cl, avail; - unsigned long idle; - int e, r; - u32 data; - - avail = card->tst_size - 2; - for (e = 0; e < avail; e++) { - if (card->soft_tst[e].vc == NULL) - break; - } - if (e >= avail) { - printk("%s: No free TST entries found\n", card->name); - return -1; - } - - NPRINTK("%s: conn %d: first TST entry at %d.\n", - card->name, vc ? vc->index : -1, e); - - r = n; - cl = avail; - data = opc & TSTE_OPC_MASK; - if (vc && (opc != TSTE_OPC_NULL)) - data = opc | vc->index; - - idle = card->tst[card->tst_index ^ 1]; - - /* - * Fill Soft TST. - */ - while (r > 0) { - if ((cl >= avail) && (card->soft_tst[e].vc == NULL)) { - if (vc) - card->soft_tst[e].vc = vc; - else - card->soft_tst[e].vc = (void *)-1; - - card->soft_tst[e].tste = data; - if (timer_pending(&card->tst_timer)) - card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE; - else { - write_sram(card, idle + e, data); - card->soft_tst[e].tste |= TSTE_PUSH_IDLE; - } - - cl -= card->tst_size; - r--; - } - - if (++e == avail) - e = 0; - cl += n; - } - - return 0; -} - -static int -fill_tst(struct idt77252_dev *card, struct vc_map *vc, int n, unsigned int opc) -{ - unsigned long flags; - int res; - - spin_lock_irqsave(&card->tst_lock, flags); - - res = __fill_tst(card, vc, n, opc); - - set_bit(TST_SWITCH_PENDING, &card->tst_state); - if (!timer_pending(&card->tst_timer)) - mod_timer(&card->tst_timer, jiffies + 1); - - spin_unlock_irqrestore(&card->tst_lock, flags); - return res; -} - -static int -__clear_tst(struct idt77252_dev *card, struct vc_map *vc) -{ - unsigned long idle; - int e; - - idle = card->tst[card->tst_index ^ 1]; - - for (e = 0; e < card->tst_size - 2; e++) { - if (card->soft_tst[e].vc == vc) { - card->soft_tst[e].vc = NULL; - - card->soft_tst[e].tste = TSTE_OPC_VAR; - if (timer_pending(&card->tst_timer)) - card->soft_tst[e].tste |= TSTE_PUSH_ACTIVE; - else { - write_sram(card, idle + e, TSTE_OPC_VAR); - card->soft_tst[e].tste |= TSTE_PUSH_IDLE; - } - } - } - - return 0; -} - -static int -clear_tst(struct idt77252_dev *card, struct vc_map *vc) -{ - unsigned long flags; - int res; - - spin_lock_irqsave(&card->tst_lock, flags); - - res = __clear_tst(card, vc); - - set_bit(TST_SWITCH_PENDING, &card->tst_state); - if (!timer_pending(&card->tst_timer)) - mod_timer(&card->tst_timer, jiffies + 1); - - spin_unlock_irqrestore(&card->tst_lock, flags); - return res; -} - -static int -change_tst(struct idt77252_dev *card, struct vc_map *vc, - int n, unsigned int opc) -{ - unsigned long flags; - int res; - - spin_lock_irqsave(&card->tst_lock, flags); - - __clear_tst(card, vc); - res = __fill_tst(card, vc, n, opc); - - set_bit(TST_SWITCH_PENDING, &card->tst_state); - if (!timer_pending(&card->tst_timer)) - mod_timer(&card->tst_timer, jiffies + 1); - - spin_unlock_irqrestore(&card->tst_lock, flags); - return res; -} - - -static int -set_tct(struct idt77252_dev *card, struct vc_map *vc) -{ - unsigned long tct; - - tct = (unsigned long) (card->tct_base + vc->index * SAR_SRAM_TCT_SIZE); - - switch (vc->class) { - case SCHED_CBR: - OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", - card->name, tct, vc->scq->scd); - - write_sram(card, tct + 0, TCT_CBR | vc->scq->scd); - write_sram(card, tct + 1, 0); - write_sram(card, tct + 2, 0); - write_sram(card, tct + 3, 0); - write_sram(card, tct + 4, 0); - write_sram(card, tct + 5, 0); - write_sram(card, tct + 6, 0); - write_sram(card, tct + 7, 0); - break; - - case SCHED_UBR: - OPRINTK("%s: writing TCT at 0x%lx, SCD 0x%lx.\n", - card->name, tct, vc->scq->scd); - - write_sram(card, tct + 0, TCT_UBR | vc->scq->scd); - write_sram(card, tct + 1, 0); - write_sram(card, tct + 2, TCT_TSIF); - write_sram(card, tct + 3, TCT_HALT | TCT_IDLE); - write_sram(card, tct + 4, 0); - write_sram(card, tct + 5, vc->init_er); - write_sram(card, tct + 6, 0); - write_sram(card, tct + 7, TCT_FLAG_UBR); - break; - - case SCHED_VBR: - case SCHED_ABR: - default: - return -ENOSYS; - } - - return 0; -} - -/*****************************************************************************/ -/* */ -/* FBQ Handling */ -/* */ -/*****************************************************************************/ - -static __inline__ int -idt77252_fbq_full(struct idt77252_dev *card, int queue) -{ - return (readl(SAR_REG_STAT) >> (16 + (queue << 2))) == 0x0f; -} - -static int -push_rx_skb(struct idt77252_dev *card, struct sk_buff *skb, int queue) -{ - unsigned long flags; - u32 handle; - u32 addr; - - skb->data = skb->head; - skb_reset_tail_pointer(skb); - skb->len = 0; - - skb_reserve(skb, 16); - - switch (queue) { - case 0: - skb_put(skb, SAR_FB_SIZE_0); - break; - case 1: - skb_put(skb, SAR_FB_SIZE_1); - break; - case 2: - skb_put(skb, SAR_FB_SIZE_2); - break; - case 3: - skb_put(skb, SAR_FB_SIZE_3); - break; - default: - return -1; - } - - if (idt77252_fbq_full(card, queue)) - return -1; - - memset(&skb->data[(skb->len & ~(0x3f)) - 64], 0, 2 * sizeof(u32)); - - handle = IDT77252_PRV_POOL(skb); - addr = IDT77252_PRV_PADDR(skb); - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(handle, card->fbq[queue]); - writel(addr, card->fbq[queue]); - spin_unlock_irqrestore(&card->cmd_lock, flags); - - return 0; -} - -static void -add_rx_skb(struct idt77252_dev *card, int queue, - unsigned int size, unsigned int count) -{ - struct sk_buff *skb; - dma_addr_t paddr; - - while (count--) { - skb = dev_alloc_skb(size); - if (!skb) - return; - - if (sb_pool_add(card, skb, queue)) { - printk("%s: SB POOL full\n", __func__); - goto outfree; - } - - paddr = dma_map_single(&card->pcidev->dev, skb->data, - skb_end_pointer(skb) - skb->data, - DMA_FROM_DEVICE); - if (dma_mapping_error(&card->pcidev->dev, paddr)) - goto outpoolrm; - IDT77252_PRV_PADDR(skb) = paddr; - - if (push_rx_skb(card, skb, queue)) { - printk("%s: FB QUEUE full\n", __func__); - goto outunmap; - } - } - - return; - -outunmap: - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, DMA_FROM_DEVICE); - -outpoolrm: - sb_pool_remove(card, skb); - -outfree: - dev_kfree_skb(skb); -} - - -static void -recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb) -{ - u32 handle = IDT77252_PRV_POOL(skb); - int err; - - dma_sync_single_for_device(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - DMA_FROM_DEVICE); - - err = push_rx_skb(card, skb, POOL_QUEUE(handle)); - if (err) { - dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb), - skb_end_pointer(skb) - skb->data, - DMA_FROM_DEVICE); - sb_pool_remove(card, skb); - dev_kfree_skb(skb); - } -} - -static void -flush_rx_pool(struct idt77252_dev *card, struct rx_pool *rpp) -{ - skb_queue_head_init(&rpp->queue); - rpp->len = 0; -} - -static void -recycle_rx_pool_skb(struct idt77252_dev *card, struct rx_pool *rpp) -{ - struct sk_buff *skb, *tmp; - - skb_queue_walk_safe(&rpp->queue, skb, tmp) - recycle_rx_skb(card, skb); - - flush_rx_pool(card, rpp); -} - -/*****************************************************************************/ -/* */ -/* ATM Interface */ -/* */ -/*****************************************************************************/ - -static void -idt77252_phy_put(struct atm_dev *dev, unsigned char value, unsigned long addr) -{ - write_utility(dev->dev_data, 0x100 + (addr & 0x1ff), value); -} - -static unsigned char -idt77252_phy_get(struct atm_dev *dev, unsigned long addr) -{ - return read_utility(dev->dev_data, 0x100 + (addr & 0x1ff)); -} - -static inline int -idt77252_send_skb(struct atm_vcc *vcc, struct sk_buff *skb, int oam) -{ - struct atm_dev *dev = vcc->dev; - struct idt77252_dev *card = dev->dev_data; - struct vc_map *vc = vcc->dev_data; - int err; - - if (vc == NULL) { - printk("%s: NULL connection in send().\n", card->name); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb(skb); - return -EINVAL; - } - if (!test_bit(VCF_TX, &vc->flags)) { - printk("%s: Trying to transmit on a non-tx VC.\n", card->name); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb(skb); - return -EINVAL; - } - - switch (vcc->qos.aal) { - case ATM_AAL0: - case ATM_AAL1: - case ATM_AAL5: - break; - default: - printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb(skb); - return -EINVAL; - } - - if (skb_shinfo(skb)->nr_frags != 0) { - printk("%s: No scatter-gather yet.\n", card->name); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb(skb); - return -EINVAL; - } - ATM_SKB(skb)->vcc = vcc; - - err = queue_skb(card, vc, skb, oam); - if (err) { - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb(skb); - return err; - } - - return 0; -} - -static int idt77252_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - return idt77252_send_skb(vcc, skb, 0); -} - -static int -idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags) -{ - struct atm_dev *dev = vcc->dev; - struct idt77252_dev *card = dev->dev_data; - struct sk_buff *skb; - - skb = dev_alloc_skb(64); - if (!skb) { - printk("%s: Out of memory in send_oam().\n", card->name); - atomic_inc(&vcc->stats->tx_err); - return -ENOMEM; - } - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc); - - skb_put_data(skb, cell, 52); - - return idt77252_send_skb(vcc, skb, 1); -} - -static __inline__ unsigned int -idt77252_fls(unsigned int x) -{ - int r = 1; - - if (x == 0) - return 0; - if (x & 0xffff0000) { - x >>= 16; - r += 16; - } - if (x & 0xff00) { - x >>= 8; - r += 8; - } - if (x & 0xf0) { - x >>= 4; - r += 4; - } - if (x & 0xc) { - x >>= 2; - r += 2; - } - if (x & 0x2) - r += 1; - return r; -} - -static u16 -idt77252_int_to_atmfp(unsigned int rate) -{ - u16 m, e; - - if (rate == 0) - return 0; - e = idt77252_fls(rate) - 1; - if (e < 9) - m = (rate - (1 << e)) << (9 - e); - else if (e == 9) - m = (rate - (1 << e)); - else /* e > 9 */ - m = (rate - (1 << e)) >> (e - 9); - return 0x4000 | (e << 9) | m; -} - -static u8 -idt77252_rate_logindex(struct idt77252_dev *card, int pcr) -{ - u16 afp; - - afp = idt77252_int_to_atmfp(pcr < 0 ? -pcr : pcr); - if (pcr < 0) - return rate_to_log[(afp >> 5) & 0x1ff]; - return rate_to_log[((afp >> 5) + 1) & 0x1ff]; -} - -static void -idt77252_est_timer(struct timer_list *t) -{ - struct rate_estimator *est = timer_container_of(est, t, timer); - struct vc_map *vc = est->vc; - struct idt77252_dev *card = vc->card; - unsigned long flags; - u32 rate, cps; - u64 ncells; - u8 lacr; - - spin_lock_irqsave(&vc->lock, flags); - if (!vc->estimator) - goto out; - ncells = est->cells; - - rate = ((u32)(ncells - est->last_cells)) << (7 - est->interval); - est->last_cells = ncells; - est->avcps += ((long)rate - (long)est->avcps) >> est->ewma_log; - est->cps = (est->avcps + 0x1f) >> 5; - - cps = est->cps; - if (cps < (est->maxcps >> 4)) - cps = est->maxcps >> 4; - - lacr = idt77252_rate_logindex(card, cps); - if (lacr > vc->max_er) - lacr = vc->max_er; - - if (lacr != vc->lacr) { - vc->lacr = lacr; - writel(TCMDQ_LACR|(vc->lacr << 16)|vc->index, SAR_REG_TCMDQ); - } - - est->timer.expires = jiffies + ((HZ / 4) << est->interval); - add_timer(&est->timer); - -out: - spin_unlock_irqrestore(&vc->lock, flags); -} - -static struct rate_estimator * -idt77252_init_est(struct vc_map *vc, int pcr) -{ - struct rate_estimator *est; - - est = kzalloc_obj(struct rate_estimator); - if (!est) - return NULL; - est->maxcps = pcr < 0 ? -pcr : pcr; - est->cps = est->maxcps; - est->avcps = est->cps << 5; - est->vc = vc; - - est->interval = 2; /* XXX: make this configurable */ - est->ewma_log = 2; /* XXX: make this configurable */ - timer_setup(&est->timer, idt77252_est_timer, 0); - mod_timer(&est->timer, jiffies + ((HZ / 4) << est->interval)); - - return est; -} - -static int -idt77252_init_cbr(struct idt77252_dev *card, struct vc_map *vc, - struct atm_vcc *vcc, struct atm_qos *qos) -{ - int tst_free, tst_used, tst_entries; - unsigned long tmpl, modl; - int tcr, tcra; - - if ((qos->txtp.max_pcr == 0) && - (qos->txtp.pcr == 0) && (qos->txtp.min_pcr == 0)) { - printk("%s: trying to open a CBR VC with cell rate = 0\n", - card->name); - return -EINVAL; - } - - tst_used = 0; - tst_free = card->tst_free; - if (test_bit(VCF_TX, &vc->flags)) - tst_used = vc->ntste; - tst_free += tst_used; - - tcr = atm_pcr_goal(&qos->txtp); - tcra = tcr >= 0 ? tcr : -tcr; - - TXPRINTK("%s: CBR target cell rate = %d\n", card->name, tcra); - - tmpl = (unsigned long) tcra * ((unsigned long) card->tst_size - 2); - modl = tmpl % (unsigned long)card->utopia_pcr; - - tst_entries = (int) (tmpl / card->utopia_pcr); - if (tcr > 0) { - if (modl > 0) - tst_entries++; - } else if (tcr == 0) { - tst_entries = tst_free - SAR_TST_RESERVED; - if (tst_entries <= 0) { - printk("%s: no CBR bandwidth free.\n", card->name); - return -ENOSR; - } - } - - if (tst_entries == 0) { - printk("%s: selected CBR bandwidth < granularity.\n", - card->name); - return -EINVAL; - } - - if (tst_entries > (tst_free - SAR_TST_RESERVED)) { - printk("%s: not enough CBR bandwidth free.\n", card->name); - return -ENOSR; - } - - vc->ntste = tst_entries; - - card->tst_free = tst_free - tst_entries; - if (test_bit(VCF_TX, &vc->flags)) { - if (tst_used == tst_entries) - return 0; - - OPRINTK("%s: modify %d -> %d entries in TST.\n", - card->name, tst_used, tst_entries); - change_tst(card, vc, tst_entries, TSTE_OPC_CBR); - return 0; - } - - OPRINTK("%s: setting %d entries in TST.\n", card->name, tst_entries); - fill_tst(card, vc, tst_entries, TSTE_OPC_CBR); - return 0; -} - -static int -idt77252_init_ubr(struct idt77252_dev *card, struct vc_map *vc, - struct atm_vcc *vcc, struct atm_qos *qos) -{ - struct rate_estimator *est = NULL; - unsigned long flags; - int tcr; - - spin_lock_irqsave(&vc->lock, flags); - if (vc->estimator) { - est = vc->estimator; - vc->estimator = NULL; - } - spin_unlock_irqrestore(&vc->lock, flags); - if (est) { - timer_shutdown_sync(&est->timer); - kfree(est); - } - - tcr = atm_pcr_goal(&qos->txtp); - if (tcr == 0) - tcr = card->link_pcr; - - vc->estimator = idt77252_init_est(vc, tcr); - - vc->class = SCHED_UBR; - vc->init_er = idt77252_rate_logindex(card, tcr); - vc->lacr = vc->init_er; - if (tcr < 0) - vc->max_er = vc->init_er; - else - vc->max_er = 0xff; - - return 0; -} - -static int -idt77252_init_tx(struct idt77252_dev *card, struct vc_map *vc, - struct atm_vcc *vcc, struct atm_qos *qos) -{ - int error; - - if (test_bit(VCF_TX, &vc->flags)) - return -EBUSY; - - switch (qos->txtp.traffic_class) { - case ATM_CBR: - vc->class = SCHED_CBR; - break; - - case ATM_UBR: - vc->class = SCHED_UBR; - break; - - case ATM_VBR: - case ATM_ABR: - default: - return -EPROTONOSUPPORT; - } - - vc->scq = alloc_scq(card, vc->class); - if (!vc->scq) { - printk("%s: can't get SCQ.\n", card->name); - return -ENOMEM; - } - - vc->scq->scd = get_free_scd(card, vc); - if (vc->scq->scd == 0) { - printk("%s: no SCD available.\n", card->name); - free_scq(card, vc->scq); - return -ENOMEM; - } - - fill_scd(card, vc->scq, vc->class); - - if (set_tct(card, vc)) { - printk("%s: class %d not supported.\n", - card->name, qos->txtp.traffic_class); - - card->scd2vc[vc->scd_index] = NULL; - free_scq(card, vc->scq); - return -EPROTONOSUPPORT; - } - - switch (vc->class) { - case SCHED_CBR: - error = idt77252_init_cbr(card, vc, vcc, qos); - if (error) { - card->scd2vc[vc->scd_index] = NULL; - free_scq(card, vc->scq); - return error; - } - - clear_bit(VCF_IDLE, &vc->flags); - writel(TCMDQ_START | vc->index, SAR_REG_TCMDQ); - break; - - case SCHED_UBR: - error = idt77252_init_ubr(card, vc, vcc, qos); - if (error) { - card->scd2vc[vc->scd_index] = NULL; - free_scq(card, vc->scq); - return error; - } - - set_bit(VCF_IDLE, &vc->flags); - break; - } - - vc->tx_vcc = vcc; - set_bit(VCF_TX, &vc->flags); - return 0; -} - -static int -idt77252_init_rx(struct idt77252_dev *card, struct vc_map *vc, - struct atm_vcc *vcc, struct atm_qos *qos) -{ - unsigned long flags; - unsigned long addr; - u32 rcte = 0; - - if (test_bit(VCF_RX, &vc->flags)) - return -EBUSY; - - vc->rx_vcc = vcc; - set_bit(VCF_RX, &vc->flags); - - if ((vcc->vci == 3) || (vcc->vci == 4)) - return 0; - - flush_rx_pool(card, &vc->rcv.rx_pool); - - rcte |= SAR_RCTE_CONNECTOPEN; - rcte |= SAR_RCTE_RAWCELLINTEN; - - switch (qos->aal) { - case ATM_AAL0: - rcte |= SAR_RCTE_RCQ; - break; - case ATM_AAL1: - rcte |= SAR_RCTE_OAM; /* Let SAR drop Video */ - break; - case ATM_AAL34: - rcte |= SAR_RCTE_AAL34; - break; - case ATM_AAL5: - rcte |= SAR_RCTE_AAL5; - break; - default: - rcte |= SAR_RCTE_RCQ; - break; - } - - if (qos->aal != ATM_AAL5) - rcte |= SAR_RCTE_FBP_1; - else if (qos->rxtp.max_sdu > SAR_FB_SIZE_2) - rcte |= SAR_RCTE_FBP_3; - else if (qos->rxtp.max_sdu > SAR_FB_SIZE_1) - rcte |= SAR_RCTE_FBP_2; - else if (qos->rxtp.max_sdu > SAR_FB_SIZE_0) - rcte |= SAR_RCTE_FBP_1; - else - rcte |= SAR_RCTE_FBP_01; - - addr = card->rct_base + (vc->index << 2); - - OPRINTK("%s: writing RCT at 0x%lx\n", card->name, addr); - write_sram(card, addr, rcte); - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); - - return 0; -} - -static int -idt77252_open(struct atm_vcc *vcc) -{ - struct atm_dev *dev = vcc->dev; - struct idt77252_dev *card = dev->dev_data; - struct vc_map *vc; - unsigned int index; - unsigned int inuse; - int error; - int vci = vcc->vci; - short vpi = vcc->vpi; - - if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC) - return 0; - - if (vpi >= (1 << card->vpibits)) { - printk("%s: unsupported VPI: %d\n", card->name, vpi); - return -EINVAL; - } - - if (vci >= (1 << card->vcibits)) { - printk("%s: unsupported VCI: %d\n", card->name, vci); - return -EINVAL; - } - - set_bit(ATM_VF_ADDR, &vcc->flags); - - mutex_lock(&card->mutex); - - OPRINTK("%s: opening vpi.vci: %d.%d\n", card->name, vpi, vci); - - switch (vcc->qos.aal) { - case ATM_AAL0: - case ATM_AAL1: - case ATM_AAL5: - break; - default: - printk("%s: Unsupported AAL: %d\n", card->name, vcc->qos.aal); - mutex_unlock(&card->mutex); - return -EPROTONOSUPPORT; - } - - index = VPCI2VC(card, vpi, vci); - if (!card->vcs[index]) { - card->vcs[index] = kzalloc_obj(struct vc_map); - if (!card->vcs[index]) { - printk("%s: can't alloc vc in open()\n", card->name); - mutex_unlock(&card->mutex); - return -ENOMEM; - } - card->vcs[index]->card = card; - card->vcs[index]->index = index; - - spin_lock_init(&card->vcs[index]->lock); - } - vc = card->vcs[index]; - - vcc->dev_data = vc; - - IPRINTK("%s: idt77252_open: vc = %d (%d.%d) %s/%s (max RX SDU: %u)\n", - card->name, vc->index, vcc->vpi, vcc->vci, - vcc->qos.rxtp.traffic_class != ATM_NONE ? "rx" : "--", - vcc->qos.txtp.traffic_class != ATM_NONE ? "tx" : "--", - vcc->qos.rxtp.max_sdu); - - inuse = 0; - if (vcc->qos.txtp.traffic_class != ATM_NONE && - test_bit(VCF_TX, &vc->flags)) - inuse = 1; - if (vcc->qos.rxtp.traffic_class != ATM_NONE && - test_bit(VCF_RX, &vc->flags)) - inuse += 2; - - if (inuse) { - printk("%s: %s vci already in use.\n", card->name, - inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); - mutex_unlock(&card->mutex); - return -EADDRINUSE; - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - error = idt77252_init_tx(card, vc, vcc, &vcc->qos); - if (error) { - mutex_unlock(&card->mutex); - return error; - } - } - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - error = idt77252_init_rx(card, vc, vcc, &vcc->qos); - if (error) { - mutex_unlock(&card->mutex); - return error; - } - } - - set_bit(ATM_VF_READY, &vcc->flags); - - mutex_unlock(&card->mutex); - return 0; -} - -static void -idt77252_close(struct atm_vcc *vcc) -{ - struct atm_dev *dev = vcc->dev; - struct idt77252_dev *card = dev->dev_data; - struct vc_map *vc = vcc->dev_data; - unsigned long flags; - unsigned long addr; - unsigned long timeout; - - mutex_lock(&card->mutex); - - IPRINTK("%s: idt77252_close: vc = %d (%d.%d)\n", - card->name, vc->index, vcc->vpi, vcc->vci); - - clear_bit(ATM_VF_READY, &vcc->flags); - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - - spin_lock_irqsave(&vc->lock, flags); - clear_bit(VCF_RX, &vc->flags); - vc->rx_vcc = NULL; - spin_unlock_irqrestore(&vc->lock, flags); - - if ((vcc->vci == 3) || (vcc->vci == 4)) - goto done; - - addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE; - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); - - if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) { - DPRINTK("%s: closing a VC with pending rx buffers.\n", - card->name); - - recycle_rx_pool_skb(card, &vc->rcv.rx_pool); - } - } - -done: - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - - spin_lock_irqsave(&vc->lock, flags); - clear_bit(VCF_TX, &vc->flags); - clear_bit(VCF_IDLE, &vc->flags); - clear_bit(VCF_RSV, &vc->flags); - vc->tx_vcc = NULL; - - if (vc->estimator) { - timer_shutdown(&vc->estimator->timer); - kfree(vc->estimator); - vc->estimator = NULL; - } - spin_unlock_irqrestore(&vc->lock, flags); - - timeout = 5 * 1000; - while (atomic_read(&vc->scq->used) > 0) { - timeout = msleep_interruptible(timeout); - if (!timeout) { - pr_warn("%s: SCQ drain timeout: %u used\n", - card->name, atomic_read(&vc->scq->used)); - break; - } - } - - writel(TCMDQ_HALT | vc->index, SAR_REG_TCMDQ); - clear_scd(card, vc->scq, vc->class); - - if (vc->class == SCHED_CBR) { - clear_tst(card, vc); - card->tst_free += vc->ntste; - vc->ntste = 0; - } - - card->scd2vc[vc->scd_index] = NULL; - free_scq(card, vc->scq); - } - - mutex_unlock(&card->mutex); -} - -static int -idt77252_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) -{ - struct atm_dev *dev = vcc->dev; - struct idt77252_dev *card = dev->dev_data; - struct vc_map *vc = vcc->dev_data; - int error = 0; - - mutex_lock(&card->mutex); - - if (qos->txtp.traffic_class != ATM_NONE) { - if (!test_bit(VCF_TX, &vc->flags)) { - error = idt77252_init_tx(card, vc, vcc, qos); - if (error) - goto out; - } else { - switch (qos->txtp.traffic_class) { - case ATM_CBR: - error = idt77252_init_cbr(card, vc, vcc, qos); - if (error) - goto out; - break; - - case ATM_UBR: - error = idt77252_init_ubr(card, vc, vcc, qos); - if (error) - goto out; - - if (!test_bit(VCF_IDLE, &vc->flags)) { - writel(TCMDQ_LACR | (vc->lacr << 16) | - vc->index, SAR_REG_TCMDQ); - } - break; - - case ATM_VBR: - case ATM_ABR: - error = -EOPNOTSUPP; - goto out; - } - } - } - - if ((qos->rxtp.traffic_class != ATM_NONE) && - !test_bit(VCF_RX, &vc->flags)) { - error = idt77252_init_rx(card, vc, vcc, qos); - if (error) - goto out; - } - - memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); - - set_bit(ATM_VF_HASQOS, &vcc->flags); - -out: - mutex_unlock(&card->mutex); - return error; -} - -static int -idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page) -{ - struct idt77252_dev *card = dev->dev_data; - int i, left; - - left = (int) *pos; - if (!left--) - return sprintf(page, "IDT77252 Interrupts:\n"); - if (!left--) - return sprintf(page, "TSIF: %lu\n", card->irqstat[15]); - if (!left--) - return sprintf(page, "TXICP: %lu\n", card->irqstat[14]); - if (!left--) - return sprintf(page, "TSQF: %lu\n", card->irqstat[12]); - if (!left--) - return sprintf(page, "TMROF: %lu\n", card->irqstat[11]); - if (!left--) - return sprintf(page, "PHYI: %lu\n", card->irqstat[10]); - if (!left--) - return sprintf(page, "FBQ3A: %lu\n", card->irqstat[8]); - if (!left--) - return sprintf(page, "FBQ2A: %lu\n", card->irqstat[7]); - if (!left--) - return sprintf(page, "RSQF: %lu\n", card->irqstat[6]); - if (!left--) - return sprintf(page, "EPDU: %lu\n", card->irqstat[5]); - if (!left--) - return sprintf(page, "RAWCF: %lu\n", card->irqstat[4]); - if (!left--) - return sprintf(page, "FBQ1A: %lu\n", card->irqstat[3]); - if (!left--) - return sprintf(page, "FBQ0A: %lu\n", card->irqstat[2]); - if (!left--) - return sprintf(page, "RSQAF: %lu\n", card->irqstat[1]); - if (!left--) - return sprintf(page, "IDT77252 Transmit Connection Table:\n"); - - for (i = 0; i < card->tct_size; i++) { - unsigned long tct; - struct atm_vcc *vcc; - struct vc_map *vc; - char *p; - - vc = card->vcs[i]; - if (!vc) - continue; - - vcc = NULL; - if (vc->tx_vcc) - vcc = vc->tx_vcc; - if (!vcc) - continue; - if (left--) - continue; - - p = page; - p += sprintf(p, " %4u: %u.%u: ", i, vcc->vpi, vcc->vci); - tct = (unsigned long) (card->tct_base + i * SAR_SRAM_TCT_SIZE); - - for (i = 0; i < 8; i++) - p += sprintf(p, " %08x", read_sram(card, tct + i)); - p += sprintf(p, "\n"); - return p - page; - } - return 0; -} - -/*****************************************************************************/ -/* */ -/* Interrupt handler */ -/* */ -/*****************************************************************************/ - -static void -idt77252_collect_stat(struct idt77252_dev *card) -{ - (void) readl(SAR_REG_CDC); - (void) readl(SAR_REG_VPEC); - (void) readl(SAR_REG_ICC); - -} - -static irqreturn_t -idt77252_interrupt(int irq, void *dev_id) -{ - struct idt77252_dev *card = dev_id; - u32 stat; - - stat = readl(SAR_REG_STAT) & 0xffff; - if (!stat) /* no interrupt for us */ - return IRQ_NONE; - - if (test_and_set_bit(IDT77252_BIT_INTERRUPT, &card->flags)) { - printk("%s: Re-entering irq_handler()\n", card->name); - goto out; - } - - writel(stat, SAR_REG_STAT); /* reset interrupt */ - - if (stat & SAR_STAT_TSIF) { /* entry written to TSQ */ - INTPRINTK("%s: TSIF\n", card->name); - card->irqstat[15]++; - idt77252_tx(card); - } - if (stat & SAR_STAT_TXICP) { /* Incomplete CS-PDU has */ - INTPRINTK("%s: TXICP\n", card->name); - card->irqstat[14]++; -#ifdef CONFIG_ATM_IDT77252_DEBUG - idt77252_tx_dump(card); -#endif - } - if (stat & SAR_STAT_TSQF) { /* TSQ 7/8 full */ - INTPRINTK("%s: TSQF\n", card->name); - card->irqstat[12]++; - idt77252_tx(card); - } - if (stat & SAR_STAT_TMROF) { /* Timer overflow */ - INTPRINTK("%s: TMROF\n", card->name); - card->irqstat[11]++; - idt77252_collect_stat(card); - } - - if (stat & SAR_STAT_EPDU) { /* Got complete CS-PDU */ - INTPRINTK("%s: EPDU\n", card->name); - card->irqstat[5]++; - idt77252_rx(card); - } - if (stat & SAR_STAT_RSQAF) { /* RSQ is 7/8 full */ - INTPRINTK("%s: RSQAF\n", card->name); - card->irqstat[1]++; - idt77252_rx(card); - } - if (stat & SAR_STAT_RSQF) { /* RSQ is full */ - INTPRINTK("%s: RSQF\n", card->name); - card->irqstat[6]++; - idt77252_rx(card); - } - if (stat & SAR_STAT_RAWCF) { /* Raw cell received */ - INTPRINTK("%s: RAWCF\n", card->name); - card->irqstat[4]++; - idt77252_rx_raw(card); - } - - if (stat & SAR_STAT_PHYI) { /* PHY device interrupt */ - INTPRINTK("%s: PHYI", card->name); - card->irqstat[10]++; - if (card->atmdev->phy && card->atmdev->phy->interrupt) - card->atmdev->phy->interrupt(card->atmdev); - } - - if (stat & (SAR_STAT_FBQ0A | SAR_STAT_FBQ1A | - SAR_STAT_FBQ2A | SAR_STAT_FBQ3A)) { - - writel(readl(SAR_REG_CFG) & ~(SAR_CFG_FBIE), SAR_REG_CFG); - - INTPRINTK("%s: FBQA: %04x\n", card->name, stat); - - if (stat & SAR_STAT_FBQ0A) - card->irqstat[2]++; - if (stat & SAR_STAT_FBQ1A) - card->irqstat[3]++; - if (stat & SAR_STAT_FBQ2A) - card->irqstat[7]++; - if (stat & SAR_STAT_FBQ3A) - card->irqstat[8]++; - - schedule_work(&card->tqueue); - } - -out: - clear_bit(IDT77252_BIT_INTERRUPT, &card->flags); - return IRQ_HANDLED; -} - -static void -idt77252_softint(struct work_struct *work) -{ - struct idt77252_dev *card = - container_of(work, struct idt77252_dev, tqueue); - u32 stat; - int done; - - for (done = 1; ; done = 1) { - stat = readl(SAR_REG_STAT) >> 16; - - if ((stat & 0x0f) < SAR_FBQ0_HIGH) { - add_rx_skb(card, 0, SAR_FB_SIZE_0, 32); - done = 0; - } - - stat >>= 4; - if ((stat & 0x0f) < SAR_FBQ1_HIGH) { - add_rx_skb(card, 1, SAR_FB_SIZE_1, 32); - done = 0; - } - - stat >>= 4; - if ((stat & 0x0f) < SAR_FBQ2_HIGH) { - add_rx_skb(card, 2, SAR_FB_SIZE_2, 32); - done = 0; - } - - stat >>= 4; - if ((stat & 0x0f) < SAR_FBQ3_HIGH) { - add_rx_skb(card, 3, SAR_FB_SIZE_3, 32); - done = 0; - } - - if (done) - break; - } - - writel(readl(SAR_REG_CFG) | SAR_CFG_FBIE, SAR_REG_CFG); -} - - -static int -open_card_oam(struct idt77252_dev *card) -{ - unsigned long flags; - unsigned long addr; - struct vc_map *vc; - int vpi, vci; - int index; - u32 rcte; - - for (vpi = 0; vpi < (1 << card->vpibits); vpi++) { - for (vci = 3; vci < 5; vci++) { - index = VPCI2VC(card, vpi, vci); - - vc = kzalloc_obj(struct vc_map); - if (!vc) { - printk("%s: can't alloc vc\n", card->name); - return -ENOMEM; - } - vc->index = index; - card->vcs[index] = vc; - - flush_rx_pool(card, &vc->rcv.rx_pool); - - rcte = SAR_RCTE_CONNECTOPEN | - SAR_RCTE_RAWCELLINTEN | - SAR_RCTE_RCQ | - SAR_RCTE_FBP_1; - - addr = card->rct_base + (vc->index << 2); - write_sram(card, addr, rcte); - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_OPEN_CONNECTION | (addr << 2), - SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); - } - } - - return 0; -} - -static void -close_card_oam(struct idt77252_dev *card) -{ - unsigned long flags; - unsigned long addr; - struct vc_map *vc; - int vpi, vci; - int index; - - for (vpi = 0; vpi < (1 << card->vpibits); vpi++) { - for (vci = 3; vci < 5; vci++) { - index = VPCI2VC(card, vpi, vci); - vc = card->vcs[index]; - - addr = card->rct_base + vc->index * SAR_SRAM_RCT_SIZE; - - spin_lock_irqsave(&card->cmd_lock, flags); - writel(SAR_CMD_CLOSE_CONNECTION | (addr << 2), - SAR_REG_CMD); - waitfor_idle(card); - spin_unlock_irqrestore(&card->cmd_lock, flags); - - if (skb_queue_len(&vc->rcv.rx_pool.queue) != 0) { - DPRINTK("%s: closing a VC " - "with pending rx buffers.\n", - card->name); - - recycle_rx_pool_skb(card, &vc->rcv.rx_pool); - } - kfree(vc); - } - } -} - -static int -open_card_ubr0(struct idt77252_dev *card) -{ - struct vc_map *vc; - - vc = kzalloc_obj(struct vc_map); - if (!vc) { - printk("%s: can't alloc vc\n", card->name); - return -ENOMEM; - } - card->vcs[0] = vc; - vc->class = SCHED_UBR0; - - vc->scq = alloc_scq(card, vc->class); - if (!vc->scq) { - printk("%s: can't get SCQ.\n", card->name); - kfree(card->vcs[0]); - card->vcs[0] = NULL; - return -ENOMEM; - } - - card->scd2vc[0] = vc; - vc->scd_index = 0; - vc->scq->scd = card->scd_base; - - fill_scd(card, vc->scq, vc->class); - - write_sram(card, card->tct_base + 0, TCT_UBR | card->scd_base); - write_sram(card, card->tct_base + 1, 0); - write_sram(card, card->tct_base + 2, 0); - write_sram(card, card->tct_base + 3, 0); - write_sram(card, card->tct_base + 4, 0); - write_sram(card, card->tct_base + 5, 0); - write_sram(card, card->tct_base + 6, 0); - write_sram(card, card->tct_base + 7, TCT_FLAG_UBR); - - clear_bit(VCF_IDLE, &vc->flags); - writel(TCMDQ_START | 0, SAR_REG_TCMDQ); - return 0; -} - -static void -close_card_ubr0(struct idt77252_dev *card) -{ - struct vc_map *vc = card->vcs[0]; - - free_scq(card, vc->scq); - kfree(vc); -} - -static int -idt77252_dev_open(struct idt77252_dev *card) -{ - u32 conf; - - if (!test_bit(IDT77252_BIT_INIT, &card->flags)) { - printk("%s: SAR not yet initialized.\n", card->name); - return -1; - } - - conf = SAR_CFG_RXPTH| /* enable receive path */ - SAR_RX_DELAY | /* interrupt on complete PDU */ - SAR_CFG_RAWIE | /* interrupt enable on raw cells */ - SAR_CFG_RQFIE | /* interrupt on RSQ almost full */ - SAR_CFG_TMOIE | /* interrupt on timer overflow */ - SAR_CFG_FBIE | /* interrupt on low free buffers */ - SAR_CFG_TXEN | /* transmit operation enable */ - SAR_CFG_TXINT | /* interrupt on transmit status */ - SAR_CFG_TXUIE | /* interrupt on transmit underrun */ - SAR_CFG_TXSFI | /* interrupt on TSQ almost full */ - SAR_CFG_PHYIE /* enable PHY interrupts */ - ; - -#ifdef CONFIG_ATM_IDT77252_RCV_ALL - /* Test RAW cell receive. */ - conf |= SAR_CFG_VPECA; -#endif - - writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG); - - if (open_card_oam(card)) { - printk("%s: Error initializing OAM.\n", card->name); - return -1; - } - - if (open_card_ubr0(card)) { - printk("%s: Error initializing UBR0.\n", card->name); - return -1; - } - - IPRINTK("%s: opened IDT77252 ABR SAR.\n", card->name); - return 0; -} - -static void idt77252_dev_close(struct atm_dev *dev) -{ - struct idt77252_dev *card = dev->dev_data; - u32 conf; - - close_card_ubr0(card); - close_card_oam(card); - - conf = SAR_CFG_RXPTH | /* enable receive path */ - SAR_RX_DELAY | /* interrupt on complete PDU */ - SAR_CFG_RAWIE | /* interrupt enable on raw cells */ - SAR_CFG_RQFIE | /* interrupt on RSQ almost full */ - SAR_CFG_TMOIE | /* interrupt on timer overflow */ - SAR_CFG_FBIE | /* interrupt on low free buffers */ - SAR_CFG_TXEN | /* transmit operation enable */ - SAR_CFG_TXINT | /* interrupt on transmit status */ - SAR_CFG_TXUIE | /* interrupt on xmit underrun */ - SAR_CFG_TXSFI /* interrupt on TSQ almost full */ - ; - - writel(readl(SAR_REG_CFG) & ~(conf), SAR_REG_CFG); - - DIPRINTK("%s: closed IDT77252 ABR SAR.\n", card->name); -} - - -/*****************************************************************************/ -/* */ -/* Initialisation and Deinitialization of IDT77252 */ -/* */ -/*****************************************************************************/ - - -static void -deinit_card(struct idt77252_dev *card) -{ - struct sk_buff *skb; - int i, j; - - if (!test_bit(IDT77252_BIT_INIT, &card->flags)) { - printk("%s: SAR not yet initialized.\n", card->name); - return; - } - DIPRINTK("idt77252: deinitialize card %u\n", card->index); - - writel(0, SAR_REG_CFG); - - if (card->atmdev) - atm_dev_deregister(card->atmdev); - - for (i = 0; i < 4; i++) { - for (j = 0; j < FBQ_SIZE; j++) { - skb = card->sbpool[i].skb[j]; - if (skb) { - dma_unmap_single(&card->pcidev->dev, - IDT77252_PRV_PADDR(skb), - (skb_end_pointer(skb) - - skb->data), - DMA_FROM_DEVICE); - card->sbpool[i].skb[j] = NULL; - dev_kfree_skb(skb); - } - } - } - - vfree(card->soft_tst); - - vfree(card->scd2vc); - - vfree(card->vcs); - - if (card->raw_cell_hnd) { - dma_free_coherent(&card->pcidev->dev, 2 * sizeof(u32), - card->raw_cell_hnd, card->raw_cell_paddr); - } - - if (card->rsq.base) { - DIPRINTK("%s: Release RSQ ...\n", card->name); - deinit_rsq(card); - } - - if (card->tsq.base) { - DIPRINTK("%s: Release TSQ ...\n", card->name); - deinit_tsq(card); - } - - DIPRINTK("idt77252: Release IRQ.\n"); - free_irq(card->pcidev->irq, card); - - for (i = 0; i < 4; i++) { - if (card->fbq[i]) - iounmap(card->fbq[i]); - } - - if (card->membase) - iounmap(card->membase); - - clear_bit(IDT77252_BIT_INIT, &card->flags); - DIPRINTK("%s: Card deinitialized.\n", card->name); -} - - -static void init_sram(struct idt77252_dev *card) -{ - int i; - - for (i = 0; i < card->sramsize; i += 4) - write_sram(card, (i >> 2), 0); - - /* set SRAM layout for THIS card */ - if (card->sramsize == (512 * 1024)) { - card->tct_base = SAR_SRAM_TCT_128_BASE; - card->tct_size = (SAR_SRAM_TCT_128_TOP - card->tct_base + 1) - / SAR_SRAM_TCT_SIZE; - card->rct_base = SAR_SRAM_RCT_128_BASE; - card->rct_size = (SAR_SRAM_RCT_128_TOP - card->rct_base + 1) - / SAR_SRAM_RCT_SIZE; - card->rt_base = SAR_SRAM_RT_128_BASE; - card->scd_base = SAR_SRAM_SCD_128_BASE; - card->scd_size = (SAR_SRAM_SCD_128_TOP - card->scd_base + 1) - / SAR_SRAM_SCD_SIZE; - card->tst[0] = SAR_SRAM_TST1_128_BASE; - card->tst[1] = SAR_SRAM_TST2_128_BASE; - card->tst_size = SAR_SRAM_TST1_128_TOP - card->tst[0] + 1; - card->abrst_base = SAR_SRAM_ABRSTD_128_BASE; - card->abrst_size = SAR_ABRSTD_SIZE_8K; - card->fifo_base = SAR_SRAM_FIFO_128_BASE; - card->fifo_size = SAR_RXFD_SIZE_32K; - } else { - card->tct_base = SAR_SRAM_TCT_32_BASE; - card->tct_size = (SAR_SRAM_TCT_32_TOP - card->tct_base + 1) - / SAR_SRAM_TCT_SIZE; - card->rct_base = SAR_SRAM_RCT_32_BASE; - card->rct_size = (SAR_SRAM_RCT_32_TOP - card->rct_base + 1) - / SAR_SRAM_RCT_SIZE; - card->rt_base = SAR_SRAM_RT_32_BASE; - card->scd_base = SAR_SRAM_SCD_32_BASE; - card->scd_size = (SAR_SRAM_SCD_32_TOP - card->scd_base + 1) - / SAR_SRAM_SCD_SIZE; - card->tst[0] = SAR_SRAM_TST1_32_BASE; - card->tst[1] = SAR_SRAM_TST2_32_BASE; - card->tst_size = (SAR_SRAM_TST1_32_TOP - card->tst[0] + 1); - card->abrst_base = SAR_SRAM_ABRSTD_32_BASE; - card->abrst_size = SAR_ABRSTD_SIZE_1K; - card->fifo_base = SAR_SRAM_FIFO_32_BASE; - card->fifo_size = SAR_RXFD_SIZE_4K; - } - - /* Initialize TCT */ - for (i = 0; i < card->tct_size; i++) { - write_sram(card, i * SAR_SRAM_TCT_SIZE + 0, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 1, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 2, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 3, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 4, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 5, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 6, 0); - write_sram(card, i * SAR_SRAM_TCT_SIZE + 7, 0); - } - - /* Initialize RCT */ - for (i = 0; i < card->rct_size; i++) { - write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE, - (u32) SAR_RCTE_RAWCELLINTEN); - write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 1, - (u32) 0); - write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 2, - (u32) 0); - write_sram(card, card->rct_base + i * SAR_SRAM_RCT_SIZE + 3, - (u32) 0xffffffff); - } - - writel((SAR_FBQ0_LOW << 28) | (SAR_FB_SIZE_0 / 48), SAR_REG_FBQS0); - writel((SAR_FBQ1_LOW << 28) | (SAR_FB_SIZE_1 / 48), SAR_REG_FBQS1); - writel((SAR_FBQ2_LOW << 28) | (SAR_FB_SIZE_2 / 48), SAR_REG_FBQS2); - writel((SAR_FBQ3_LOW << 28) | (SAR_FB_SIZE_3 / 48), SAR_REG_FBQS3); - - /* Initialize rate table */ - for (i = 0; i < 256; i++) { - write_sram(card, card->rt_base + i, log_to_rate[i]); - } - - for (i = 0; i < 128; i++) { - unsigned int tmp; - - tmp = rate_to_log[(i << 2) + 0] << 0; - tmp |= rate_to_log[(i << 2) + 1] << 8; - tmp |= rate_to_log[(i << 2) + 2] << 16; - tmp |= rate_to_log[(i << 2) + 3] << 24; - write_sram(card, card->rt_base + 256 + i, tmp); - } - -#if 0 /* Fill RDF and AIR tables. */ - for (i = 0; i < 128; i++) { - unsigned int tmp; - - tmp = RDF[0][(i << 1) + 0] << 16; - tmp |= RDF[0][(i << 1) + 1] << 0; - write_sram(card, card->rt_base + 512 + i, tmp); - } - - for (i = 0; i < 128; i++) { - unsigned int tmp; - - tmp = AIR[0][(i << 1) + 0] << 16; - tmp |= AIR[0][(i << 1) + 1] << 0; - write_sram(card, card->rt_base + 640 + i, tmp); - } -#endif - - IPRINTK("%s: initialize rate table ...\n", card->name); - writel(card->rt_base << 2, SAR_REG_RTBL); - - /* Initialize TSTs */ - IPRINTK("%s: initialize TST ...\n", card->name); - card->tst_free = card->tst_size - 2; /* last two are jumps */ - - for (i = card->tst[0]; i < card->tst[0] + card->tst_size - 2; i++) - write_sram(card, i, TSTE_OPC_VAR); - write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2)); - idt77252_sram_write_errors = 1; - write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2)); - idt77252_sram_write_errors = 0; - for (i = card->tst[1]; i < card->tst[1] + card->tst_size - 2; i++) - write_sram(card, i, TSTE_OPC_VAR); - write_sram(card, i++, TSTE_OPC_JMP | (card->tst[1] << 2)); - idt77252_sram_write_errors = 1; - write_sram(card, i++, TSTE_OPC_JMP | (card->tst[0] << 2)); - idt77252_sram_write_errors = 0; - - card->tst_index = 0; - writel(card->tst[0] << 2, SAR_REG_TSTB); - - /* Initialize ABRSTD and Receive FIFO */ - IPRINTK("%s: initialize ABRSTD ...\n", card->name); - writel(card->abrst_size | (card->abrst_base << 2), - SAR_REG_ABRSTD); - - IPRINTK("%s: initialize receive fifo ...\n", card->name); - writel(card->fifo_size | (card->fifo_base << 2), - SAR_REG_RXFD); - - IPRINTK("%s: SRAM initialization complete.\n", card->name); -} - -static int init_card(struct atm_dev *dev) -{ - struct idt77252_dev *card = dev->dev_data; - struct pci_dev *pcidev = card->pcidev; - unsigned long tmpl, modl; - unsigned int linkrate, rsvdcr; - unsigned int tst_entries; - struct net_device *tmp; - char tname[10]; - - u32 size; - u_char pci_byte; - u32 conf; - int i, k; - - if (test_bit(IDT77252_BIT_INIT, &card->flags)) { - printk("Error: SAR already initialized.\n"); - return -1; - } - -/*****************************************************************/ -/* P C I C O N F I G U R A T I O N */ -/*****************************************************************/ - - /* Set PCI Retry-Timeout and TRDY timeout */ - IPRINTK("%s: Checking PCI retries.\n", card->name); - if (pci_read_config_byte(pcidev, 0x40, &pci_byte) != 0) { - printk("%s: can't read PCI retry timeout.\n", card->name); - deinit_card(card); - return -1; - } - if (pci_byte != 0) { - IPRINTK("%s: PCI retry timeout: %d, set to 0.\n", - card->name, pci_byte); - if (pci_write_config_byte(pcidev, 0x40, 0) != 0) { - printk("%s: can't set PCI retry timeout.\n", - card->name); - deinit_card(card); - return -1; - } - } - IPRINTK("%s: Checking PCI TRDY.\n", card->name); - if (pci_read_config_byte(pcidev, 0x41, &pci_byte) != 0) { - printk("%s: can't read PCI TRDY timeout.\n", card->name); - deinit_card(card); - return -1; - } - if (pci_byte != 0) { - IPRINTK("%s: PCI TRDY timeout: %d, set to 0.\n", - card->name, pci_byte); - if (pci_write_config_byte(pcidev, 0x41, 0) != 0) { - printk("%s: can't set PCI TRDY timeout.\n", card->name); - deinit_card(card); - return -1; - } - } - /* Reset Timer register */ - if (readl(SAR_REG_STAT) & SAR_STAT_TMROF) { - printk("%s: resetting timer overflow.\n", card->name); - writel(SAR_STAT_TMROF, SAR_REG_STAT); - } - IPRINTK("%s: Request IRQ ... ", card->name); - if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_SHARED, - card->name, card) != 0) { - printk("%s: can't allocate IRQ.\n", card->name); - deinit_card(card); - return -1; - } - IPRINTK("got %d.\n", pcidev->irq); - -/*****************************************************************/ -/* C H E C K A N D I N I T S R A M */ -/*****************************************************************/ - - IPRINTK("%s: Initializing SRAM\n", card->name); - - /* preset size of connecton table, so that init_sram() knows about it */ - conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */ - SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */ - SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */ -#ifndef ATM_IDT77252_SEND_IDLE - SAR_CFG_NO_IDLE | /* Do not send idle cells */ -#endif - 0; - - if (card->sramsize == (512 * 1024)) - conf |= SAR_CFG_CNTBL_1k; - else - conf |= SAR_CFG_CNTBL_512; - - switch (vpibits) { - case 0: - conf |= SAR_CFG_VPVCS_0; - break; - default: - case 1: - conf |= SAR_CFG_VPVCS_1; - break; - case 2: - conf |= SAR_CFG_VPVCS_2; - break; - case 8: - conf |= SAR_CFG_VPVCS_8; - break; - } - - writel(readl(SAR_REG_CFG) | conf, SAR_REG_CFG); - - init_sram(card); - -/********************************************************************/ -/* A L L O C R A M A N D S E T V A R I O U S T H I N G S */ -/********************************************************************/ - /* Initialize TSQ */ - if (0 != init_tsq(card)) { - deinit_card(card); - return -1; - } - /* Initialize RSQ */ - if (0 != init_rsq(card)) { - deinit_card(card); - return -1; - } - - card->vpibits = vpibits; - if (card->sramsize == (512 * 1024)) { - card->vcibits = 10 - card->vpibits; - } else { - card->vcibits = 9 - card->vpibits; - } - - card->vcimask = 0; - for (k = 0, i = 1; k < card->vcibits; k++) { - card->vcimask |= i; - i <<= 1; - } - - IPRINTK("%s: Setting VPI/VCI mask to zero.\n", card->name); - writel(0, SAR_REG_VPM); - - /* Little Endian Order */ - writel(0, SAR_REG_GP); - - /* Initialize RAW Cell Handle Register */ - card->raw_cell_hnd = dma_alloc_coherent(&card->pcidev->dev, - 2 * sizeof(u32), - &card->raw_cell_paddr, - GFP_KERNEL); - if (!card->raw_cell_hnd) { - printk("%s: memory allocation failure.\n", card->name); - deinit_card(card); - return -1; - } - writel(card->raw_cell_paddr, SAR_REG_RAWHND); - IPRINTK("%s: raw cell handle is at 0x%p.\n", card->name, - card->raw_cell_hnd); - - size = sizeof(struct vc_map *) * card->tct_size; - IPRINTK("%s: allocate %d byte for VC map.\n", card->name, size); - card->vcs = vzalloc(size); - if (!card->vcs) { - printk("%s: memory allocation failure.\n", card->name); - deinit_card(card); - return -1; - } - - size = sizeof(struct vc_map *) * card->scd_size; - IPRINTK("%s: allocate %d byte for SCD to VC mapping.\n", - card->name, size); - card->scd2vc = vzalloc(size); - if (!card->scd2vc) { - printk("%s: memory allocation failure.\n", card->name); - deinit_card(card); - return -1; - } - - size = sizeof(struct tst_info) * (card->tst_size - 2); - IPRINTK("%s: allocate %d byte for TST to VC mapping.\n", - card->name, size); - card->soft_tst = vmalloc(size); - if (!card->soft_tst) { - printk("%s: memory allocation failure.\n", card->name); - deinit_card(card); - return -1; - } - for (i = 0; i < card->tst_size - 2; i++) { - card->soft_tst[i].tste = TSTE_OPC_VAR; - card->soft_tst[i].vc = NULL; - } - - if (dev->phy == NULL) { - printk("%s: No LT device defined.\n", card->name); - deinit_card(card); - return -1; - } - if (dev->phy->ioctl == NULL) { - printk("%s: LT had no IOCTL function defined.\n", card->name); - deinit_card(card); - return -1; - } - -#ifdef CONFIG_ATM_IDT77252_USE_SUNI - /* - * this is a jhs hack to get around special functionality in the - * phy driver for the atecom hardware; the functionality doesn't - * exist in the linux atm suni driver - * - * it isn't the right way to do things, but as the guy from NIST - * said, talking about their measurement of the fine structure - * constant, "it's good enough for government work." - */ - linkrate = 149760000; -#endif - - card->link_pcr = (linkrate / 8 / 53); - printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n", - card->name, linkrate, card->link_pcr); - -#ifdef ATM_IDT77252_SEND_IDLE - card->utopia_pcr = card->link_pcr; -#else - card->utopia_pcr = (160000000 / 8 / 54); -#endif - - rsvdcr = 0; - if (card->utopia_pcr > card->link_pcr) - rsvdcr = card->utopia_pcr - card->link_pcr; - - tmpl = (unsigned long) rsvdcr * ((unsigned long) card->tst_size - 2); - modl = tmpl % (unsigned long)card->utopia_pcr; - tst_entries = (int) (tmpl / (unsigned long)card->utopia_pcr); - if (modl) - tst_entries++; - card->tst_free -= tst_entries; - fill_tst(card, NULL, tst_entries, TSTE_OPC_NULL); - -#ifdef HAVE_EEPROM - idt77252_eeprom_init(card); - printk("%s: EEPROM: %02x:", card->name, - idt77252_eeprom_read_status(card)); - - for (i = 0; i < 0x80; i++) { - printk(" %02x", - idt77252_eeprom_read_byte(card, i) - ); - } - printk("\n"); -#endif /* HAVE_EEPROM */ - - /* - * XXX: - */ - sprintf(tname, "eth%d", card->index); - tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */ - if (tmp) { - memcpy(card->atmdev->esi, tmp->dev_addr, 6); - dev_put(tmp); - printk("%s: ESI %pM\n", card->name, card->atmdev->esi); - } - /* - * XXX: - */ - - /* Set Maximum Deficit Count for now. */ - writel(0xffff, SAR_REG_MDFCT); - - set_bit(IDT77252_BIT_INIT, &card->flags); - - XPRINTK("%s: IDT77252 ABR SAR initialization complete.\n", card->name); - return 0; -} - - -/*****************************************************************************/ -/* */ -/* Probing of IDT77252 ABR SAR */ -/* */ -/*****************************************************************************/ - - -static int idt77252_preset(struct idt77252_dev *card) -{ - u16 pci_command; - -/*****************************************************************/ -/* P C I C O N F I G U R A T I O N */ -/*****************************************************************/ - - XPRINTK("%s: Enable PCI master and memory access for SAR.\n", - card->name); - if (pci_read_config_word(card->pcidev, PCI_COMMAND, &pci_command)) { - printk("%s: can't read PCI_COMMAND.\n", card->name); - deinit_card(card); - return -1; - } - if (!(pci_command & PCI_COMMAND_IO)) { - printk("%s: PCI_COMMAND: %04x (?)\n", - card->name, pci_command); - deinit_card(card); - return (-1); - } - pci_command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - if (pci_write_config_word(card->pcidev, PCI_COMMAND, pci_command)) { - printk("%s: can't write PCI_COMMAND.\n", card->name); - deinit_card(card); - return -1; - } -/*****************************************************************/ -/* G E N E R I C R E S E T */ -/*****************************************************************/ - - /* Software reset */ - writel(SAR_CFG_SWRST, SAR_REG_CFG); - mdelay(1); - writel(0, SAR_REG_CFG); - - IPRINTK("%s: Software resetted.\n", card->name); - return 0; -} - - -static unsigned long probe_sram(struct idt77252_dev *card) -{ - u32 data, addr; - - writel(0, SAR_REG_DR0); - writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD); - - for (addr = 0x4000; addr < 0x80000; addr += 0x4000) { - writel(ATM_POISON, SAR_REG_DR0); - writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); - - writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD); - data = readl(SAR_REG_DR0); - - if (data != 0) - break; - } - - return addr * sizeof(u32); -} - -static int idt77252_init_one(struct pci_dev *pcidev, - const struct pci_device_id *id) -{ - static struct idt77252_dev **last = &idt77252_chain; - static int index = 0; - - unsigned long membase, srambase; - struct idt77252_dev *card; - struct atm_dev *dev; - int i, err; - - - if ((err = pci_enable_device(pcidev))) { - printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev)); - return err; - } - - if ((err = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)))) { - printk("idt77252: can't enable DMA for PCI device at %s\n", pci_name(pcidev)); - goto err_out_disable_pdev; - } - - card = kzalloc_obj(struct idt77252_dev); - if (!card) { - printk("idt77252-%d: can't allocate private data\n", index); - err = -ENOMEM; - goto err_out_disable_pdev; - } - card->revision = pcidev->revision; - card->index = index; - card->pcidev = pcidev; - sprintf(card->name, "idt77252-%d", card->index); - - INIT_WORK(&card->tqueue, idt77252_softint); - - membase = pci_resource_start(pcidev, 1); - srambase = pci_resource_start(pcidev, 2); - - mutex_init(&card->mutex); - spin_lock_init(&card->cmd_lock); - spin_lock_init(&card->tst_lock); - - timer_setup(&card->tst_timer, tst_timer, 0); - - /* Do the I/O remapping... */ - card->membase = ioremap(membase, 1024); - if (!card->membase) { - printk("%s: can't ioremap() membase\n", card->name); - err = -EIO; - goto err_out_free_card; - } - - if (idt77252_preset(card)) { - printk("%s: preset failed\n", card->name); - err = -EIO; - goto err_out_iounmap; - } - - dev = atm_dev_register("idt77252", &pcidev->dev, &idt77252_ops, -1, - NULL); - if (!dev) { - printk("%s: can't register atm device\n", card->name); - err = -EIO; - goto err_out_iounmap; - } - dev->dev_data = card; - card->atmdev = dev; - -#ifdef CONFIG_ATM_IDT77252_USE_SUNI - suni_init(dev); - if (!dev->phy) { - printk("%s: can't init SUNI\n", card->name); - err = -EIO; - goto err_out_deinit_card; - } -#endif /* CONFIG_ATM_IDT77252_USE_SUNI */ - - card->sramsize = probe_sram(card); - - for (i = 0; i < 4; i++) { - card->fbq[i] = ioremap(srambase | 0x200000 | (i << 18), 4); - if (!card->fbq[i]) { - printk("%s: can't ioremap() FBQ%d\n", card->name, i); - err = -EIO; - goto err_out_deinit_card; - } - } - - printk("%s: ABR SAR (Rev %c): MEM %08lx SRAM %08lx [%u KB]\n", - card->name, ((card->revision > 1) && (card->revision < 25)) ? - 'A' + card->revision - 1 : '?', membase, srambase, - card->sramsize / 1024); - - if (init_card(dev)) { - printk("%s: init_card failed\n", card->name); - err = -EIO; - goto err_out_deinit_card; - } - - dev->ci_range.vpi_bits = card->vpibits; - dev->ci_range.vci_bits = card->vcibits; - dev->link_rate = card->link_pcr; - - if (dev->phy->start) - dev->phy->start(dev); - - if (idt77252_dev_open(card)) { - printk("%s: dev_open failed\n", card->name); - err = -EIO; - goto err_out_stop; - } - - *last = card; - last = &card->next; - index++; - - return 0; - -err_out_stop: - if (dev->phy->stop) - dev->phy->stop(dev); - -err_out_deinit_card: - deinit_card(card); - -err_out_iounmap: - iounmap(card->membase); - -err_out_free_card: - kfree(card); - -err_out_disable_pdev: - pci_disable_device(pcidev); - return err; -} - -static const struct pci_device_id idt77252_pci_tbl[] = -{ - { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77252), 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, idt77252_pci_tbl); - -static struct pci_driver idt77252_driver = { - .name = "idt77252", - .id_table = idt77252_pci_tbl, - .probe = idt77252_init_one, -}; - -static int __init idt77252_init(void) -{ - struct sk_buff *skb; - - printk("%s: at %p\n", __func__, idt77252_init); - BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct idt77252_skb_prv) + sizeof(struct atm_skb_data)); - return pci_register_driver(&idt77252_driver); -} - -static void __exit idt77252_exit(void) -{ - struct idt77252_dev *card; - struct atm_dev *dev; - - pci_unregister_driver(&idt77252_driver); - - while (idt77252_chain) { - card = idt77252_chain; - dev = card->atmdev; - idt77252_chain = card->next; - timer_shutdown_sync(&card->tst_timer); - - if (dev->phy->stop) - dev->phy->stop(dev); - deinit_card(card); - pci_disable_device(card->pcidev); - kfree(card); - } - - DIPRINTK("idt77252: finished cleanup-module().\n"); -} - -module_init(idt77252_init); -module_exit(idt77252_exit); - -MODULE_LICENSE("GPL"); - -module_param(vpibits, uint, 0); -MODULE_PARM_DESC(vpibits, "number of VPI bits supported (0, 1, or 2)"); -#ifdef CONFIG_ATM_IDT77252_DEBUG -module_param(debug, ulong, 0644); -MODULE_PARM_DESC(debug, "debug bitmap, see drivers/atm/idt77252.h"); -#endif - -MODULE_AUTHOR("Eddie C. Dost "); -MODULE_DESCRIPTION("IDT77252 ABR SAR Driver"); diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c deleted file mode 100644 index 0d38e93772c2..000000000000 --- a/drivers/atm/iphase.c +++ /dev/null @@ -1,3283 +0,0 @@ -/****************************************************************************** - iphase.c: Device driver for Interphase ATM PCI adapter cards - Author: Peter Wang - Some fixes: Arnaldo Carvalho de Melo - Interphase Corporation - Version: 1.0 -******************************************************************************* - - This software may be used and distributed according to the terms - of the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on this skeleton fall under the GPL and must retain - the authorship (implicit copyright) notice. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - Modified from an incomplete driver for Interphase 5575 1KVC 1M card which - was originally written by Monalisa Agrawal at UNH. Now this driver - supports a variety of varients of Interphase ATM PCI (i)Chip adapter - card family (See www.iphase.com/products/ClassSheet.cfm?ClassID=ATM) - in terms of PHY type, the size of control memory and the size of - packet memory. The following are the change log and history: - - Bugfix the Mona's UBR driver. - Modify the basic memory allocation and dma logic. - Port the driver to the latest kernel from 2.0.46. - Complete the ABR logic of the driver, and added the ABR work- - around for the hardware anormalies. - Add the CBR support. - Add the flow control logic to the driver to allow rate-limit VC. - Add 4K VC support to the board with 512K control memory. - Add the support of all the variants of the Interphase ATM PCI - (i)Chip adapter cards including x575 (155M OC3 and UTP155), x525 - (25M UTP25) and x531 (DS3 and E3). - Add SMP support. - - Support and updates available at: ftp://ftp.iphase.com/pub/atm - -*******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iphase.h" -#include "suni.h" -#define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) - -#define PRIV(dev) ((struct suni_priv *) dev->phy_data) - -static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr); -static void desc_dbg(IADEV *iadev); - -static IADEV *ia_dev[8]; -static struct atm_dev *_ia_dev[8]; -static int iadev_count; -static void ia_led_timer(struct timer_list *unused); -static DEFINE_TIMER(ia_timer, ia_led_timer); -static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ; -static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ; -static uint IADebugFlag = /* IF_IADBG_ERR | IF_IADBG_CBR| IF_IADBG_INIT_ADAPTER - |IF_IADBG_ABR | IF_IADBG_EVENT*/ 0; - -module_param(IA_TX_BUF, int, 0); -module_param(IA_TX_BUF_SZ, int, 0); -module_param(IA_RX_BUF, int, 0); -module_param(IA_RX_BUF_SZ, int, 0); -module_param(IADebugFlag, uint, 0644); - -MODULE_DESCRIPTION("Driver for Interphase ATM PCI NICs"); -MODULE_LICENSE("GPL"); - -/**************************** IA_LIB **********************************/ - -static void ia_init_rtn_q (IARTN_Q *que) -{ - que->next = NULL; - que->tail = NULL; -} - -static void ia_enque_head_rtn_q (IARTN_Q *que, IARTN_Q * data) -{ - data->next = NULL; - if (que->next == NULL) - que->next = que->tail = data; - else { - data->next = que->next; - que->next = data; - } - return; -} - -static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) { - IARTN_Q *entry = kmalloc_obj(*entry, GFP_ATOMIC); - if (!entry) - return -ENOMEM; - entry->data = data; - entry->next = NULL; - if (que->next == NULL) - que->next = que->tail = entry; - else { - que->tail->next = entry; - que->tail = que->tail->next; - } - return 1; -} - -static IARTN_Q * ia_deque_rtn_q (IARTN_Q *que) { - IARTN_Q *tmpdata; - if (que->next == NULL) - return NULL; - tmpdata = que->next; - if ( que->next == que->tail) - que->next = que->tail = NULL; - else - que->next = que->next->next; - return tmpdata; -} - -static void ia_hack_tcq(IADEV *dev) { - - u_short desc1; - u_short tcq_wr; - struct ia_vcc *iavcc_r = NULL; - - tcq_wr = readl(dev->seg_reg+TCQ_WR_PTR) & 0xffff; - while (dev->host_tcq_wr != tcq_wr) { - desc1 = *(u_short *)(dev->seg_ram + dev->host_tcq_wr); - if (!desc1) ; - else if (!dev->desc_tbl[desc1 -1].timestamp) { - IF_ABR(printk(" Desc %d is reset at %ld\n", desc1 -1, jiffies);) - *(u_short *) (dev->seg_ram + dev->host_tcq_wr) = 0; - } - else if (dev->desc_tbl[desc1 -1].timestamp) { - if (!(iavcc_r = dev->desc_tbl[desc1 -1].iavcc)) { - printk("IA: Fatal err in get_desc\n"); - continue; - } - iavcc_r->vc_desc_cnt--; - dev->desc_tbl[desc1 -1].timestamp = 0; - IF_EVENT(printk("ia_hack: return_q skb = 0x%p desc = %d\n", - dev->desc_tbl[desc1 -1].txskb, desc1);) - if (iavcc_r->pcr < dev->rate_limit) { - IA_SKB_STATE (dev->desc_tbl[desc1-1].txskb) |= IA_TX_DONE; - if (ia_enque_rtn_q(&dev->tx_return_q, dev->desc_tbl[desc1 -1]) < 0) - printk("ia_hack_tcq: No memory available\n"); - } - dev->desc_tbl[desc1 -1].iavcc = NULL; - dev->desc_tbl[desc1 -1].txskb = NULL; - } - dev->host_tcq_wr += 2; - if (dev->host_tcq_wr > dev->ffL.tcq_ed) - dev->host_tcq_wr = dev->ffL.tcq_st; - } -} /* ia_hack_tcq */ - -static u16 get_desc (IADEV *dev, struct ia_vcc *iavcc) { - u_short desc_num, i; - struct ia_vcc *iavcc_r = NULL; - unsigned long delta; - static unsigned long timer = 0; - int ltimeout; - - ia_hack_tcq (dev); - if((time_after(jiffies,timer+50)) || ((dev->ffL.tcq_rd==dev->host_tcq_wr))) { - timer = jiffies; - i=0; - while (i < dev->num_tx_desc) { - if (!dev->desc_tbl[i].timestamp) { - i++; - continue; - } - ltimeout = dev->desc_tbl[i].iavcc->ltimeout; - delta = jiffies - dev->desc_tbl[i].timestamp; - if (delta >= ltimeout) { - IF_ABR(printk("RECOVER run!! desc_tbl %d = %d delta = %ld, time = %ld\n", i,dev->desc_tbl[i].timestamp, delta, jiffies);) - if (dev->ffL.tcq_rd == dev->ffL.tcq_st) - dev->ffL.tcq_rd = dev->ffL.tcq_ed; - else - dev->ffL.tcq_rd -= 2; - *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd) = i+1; - if (!dev->desc_tbl[i].txskb || !(iavcc_r = dev->desc_tbl[i].iavcc)) - printk("Fatal err, desc table vcc or skb is NULL\n"); - else - iavcc_r->vc_desc_cnt--; - dev->desc_tbl[i].timestamp = 0; - dev->desc_tbl[i].iavcc = NULL; - dev->desc_tbl[i].txskb = NULL; - } - i++; - } /* while */ - } - if (dev->ffL.tcq_rd == dev->host_tcq_wr) - return 0xFFFF; - - /* Get the next available descriptor number from TCQ */ - desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); - - while (!desc_num || (dev->desc_tbl[desc_num -1]).timestamp) { - dev->ffL.tcq_rd += 2; - if (dev->ffL.tcq_rd > dev->ffL.tcq_ed) - dev->ffL.tcq_rd = dev->ffL.tcq_st; - if (dev->ffL.tcq_rd == dev->host_tcq_wr) - return 0xFFFF; - desc_num = *(u_short *)(dev->seg_ram + dev->ffL.tcq_rd); - } - - /* get system time */ - dev->desc_tbl[desc_num -1].timestamp = jiffies; - return desc_num; -} - -static void clear_lockup (struct atm_vcc *vcc, IADEV *dev) { - u_char foundLockUp; - vcstatus_t *vcstatus; - u_short *shd_tbl; - u_short tempCellSlot, tempFract; - struct main_vc *abr_vc = (struct main_vc *)dev->MAIN_VC_TABLE_ADDR; - struct ext_vc *eabr_vc = (struct ext_vc *)dev->EXT_VC_TABLE_ADDR; - u_int i; - - if (vcc->qos.txtp.traffic_class == ATM_ABR) { - vcstatus = (vcstatus_t *) &(dev->testTable[vcc->vci]->vc_status); - vcstatus->cnt++; - foundLockUp = 0; - if( vcstatus->cnt == 0x05 ) { - abr_vc += vcc->vci; - eabr_vc += vcc->vci; - if( eabr_vc->last_desc ) { - if( (abr_vc->status & 0x07) == ABR_STATE /* 0x2 */ ) { - /* Wait for 10 Micro sec */ - udelay(10); - if ((eabr_vc->last_desc)&&((abr_vc->status & 0x07)==ABR_STATE)) - foundLockUp = 1; - } - else { - tempCellSlot = abr_vc->last_cell_slot; - tempFract = abr_vc->fraction; - if((tempCellSlot == dev->testTable[vcc->vci]->lastTime) - && (tempFract == dev->testTable[vcc->vci]->fract)) - foundLockUp = 1; - dev->testTable[vcc->vci]->lastTime = tempCellSlot; - dev->testTable[vcc->vci]->fract = tempFract; - } - } /* last descriptor */ - vcstatus->cnt = 0; - } /* vcstatus->cnt */ - - if (foundLockUp) { - IF_ABR(printk("LOCK UP found\n");) - writew(0xFFFD, dev->seg_reg+MODE_REG_0); - /* Wait for 10 Micro sec */ - udelay(10); - abr_vc->status &= 0xFFF8; - abr_vc->status |= 0x0001; /* state is idle */ - shd_tbl = (u_short *)dev->ABR_SCHED_TABLE_ADDR; - for( i = 0; ((i < dev->num_vc) && (shd_tbl[i])); i++ ); - if (i < dev->num_vc) - shd_tbl[i] = vcc->vci; - else - IF_ERR(printk("ABR Seg. may not continue on VC %x\n",vcc->vci);) - writew(T_ONLINE, dev->seg_reg+MODE_REG_0); - writew(~(TRANSMIT_DONE|TCQ_NOT_EMPTY), dev->seg_reg+SEG_MASK_REG); - writew(TRANSMIT_DONE, dev->seg_reg+SEG_INTR_STATUS_REG); - vcstatus->cnt = 0; - } /* foundLockUp */ - - } /* if an ABR VC */ - - -} - -/* -** Conversion of 24-bit cellrate (cells/sec) to 16-bit floating point format. -** -** +----+----+------------------+-------------------------------+ -** | R | NZ | 5-bit exponent | 9-bit mantissa | -** +----+----+------------------+-------------------------------+ -** -** R = reserved (written as 0) -** NZ = 0 if 0 cells/sec; 1 otherwise -** -** if NZ = 1, rate = 1.mmmmmmmmm x 2^(eeeee) cells/sec -*/ -static u16 -cellrate_to_float(u32 cr) -{ - -#define NZ 0x4000 -#define M_BITS 9 /* Number of bits in mantissa */ -#define E_BITS 5 /* Number of bits in exponent */ -#define M_MASK 0x1ff -#define E_MASK 0x1f - u16 flot; - u32 tmp = cr & 0x00ffffff; - int i = 0; - if (cr == 0) - return 0; - while (tmp != 1) { - tmp >>= 1; - i++; - } - if (i == M_BITS) - flot = NZ | (i << M_BITS) | (cr & M_MASK); - else if (i < M_BITS) - flot = NZ | (i << M_BITS) | ((cr << (M_BITS - i)) & M_MASK); - else - flot = NZ | (i << M_BITS) | ((cr >> (i - M_BITS)) & M_MASK); - return flot; -} - -#if 0 -/* -** Conversion of 16-bit floating point format to 24-bit cellrate (cells/sec). -*/ -static u32 -float_to_cellrate(u16 rate) -{ - u32 exp, mantissa, cps; - if ((rate & NZ) == 0) - return 0; - exp = (rate >> M_BITS) & E_MASK; - mantissa = rate & M_MASK; - if (exp == 0) - return 1; - cps = (1 << M_BITS) | mantissa; - if (exp == M_BITS) - cps = cps; - else if (exp > M_BITS) - cps <<= (exp - M_BITS); - else - cps >>= (M_BITS - exp); - return cps; -} -#endif - -static void init_abr_vc (IADEV *dev, srv_cls_param_t *srv_p) { - srv_p->class_type = ATM_ABR; - srv_p->pcr = dev->LineRate; - srv_p->mcr = 0; - srv_p->icr = 0x055cb7; - srv_p->tbe = 0xffffff; - srv_p->frtt = 0x3a; - srv_p->rif = 0xf; - srv_p->rdf = 0xb; - srv_p->nrm = 0x4; - srv_p->trm = 0x7; - srv_p->cdf = 0x3; - srv_p->adtf = 50; -} - -static int -ia_open_abr_vc(IADEV *dev, srv_cls_param_t *srv_p, - struct atm_vcc *vcc, u8 flag) -{ - f_vc_abr_entry *f_abr_vc; - r_vc_abr_entry *r_abr_vc; - u32 icr; - u8 trm, nrm, crm; - u16 adtf, air, *ptr16; - f_abr_vc =(f_vc_abr_entry *)dev->MAIN_VC_TABLE_ADDR; - f_abr_vc += vcc->vci; - switch (flag) { - case 1: /* FFRED initialization */ -#if 0 /* sanity check */ - if (srv_p->pcr == 0) - return INVALID_PCR; - if (srv_p->pcr > dev->LineRate) - srv_p->pcr = dev->LineRate; - if ((srv_p->mcr + dev->sum_mcr) > dev->LineRate) - return MCR_UNAVAILABLE; - if (srv_p->mcr > srv_p->pcr) - return INVALID_MCR; - if (!(srv_p->icr)) - srv_p->icr = srv_p->pcr; - if ((srv_p->icr < srv_p->mcr) || (srv_p->icr > srv_p->pcr)) - return INVALID_ICR; - if ((srv_p->tbe < MIN_TBE) || (srv_p->tbe > MAX_TBE)) - return INVALID_TBE; - if ((srv_p->frtt < MIN_FRTT) || (srv_p->frtt > MAX_FRTT)) - return INVALID_FRTT; - if (srv_p->nrm > MAX_NRM) - return INVALID_NRM; - if (srv_p->trm > MAX_TRM) - return INVALID_TRM; - if (srv_p->adtf > MAX_ADTF) - return INVALID_ADTF; - else if (srv_p->adtf == 0) - srv_p->adtf = 1; - if (srv_p->cdf > MAX_CDF) - return INVALID_CDF; - if (srv_p->rif > MAX_RIF) - return INVALID_RIF; - if (srv_p->rdf > MAX_RDF) - return INVALID_RDF; -#endif - memset ((caddr_t)f_abr_vc, 0, sizeof(*f_abr_vc)); - f_abr_vc->f_vc_type = ABR; - nrm = 2 << srv_p->nrm; /* (2 ** (srv_p->nrm +1)) */ - /* i.e 2**n = 2 << (n-1) */ - f_abr_vc->f_nrm = nrm << 8 | nrm; - trm = 100000/(2 << (16 - srv_p->trm)); - if ( trm == 0) trm = 1; - f_abr_vc->f_nrmexp =(((srv_p->nrm +1) & 0x0f) << 12)|(MRM << 8) | trm; - crm = srv_p->tbe / nrm; - if (crm == 0) crm = 1; - f_abr_vc->f_crm = crm & 0xff; - f_abr_vc->f_pcr = cellrate_to_float(srv_p->pcr); - icr = min( srv_p->icr, (srv_p->tbe > srv_p->frtt) ? - ((srv_p->tbe/srv_p->frtt)*1000000) : - (1000000/(srv_p->frtt/srv_p->tbe))); - f_abr_vc->f_icr = cellrate_to_float(icr); - adtf = (10000 * srv_p->adtf)/8192; - if (adtf == 0) adtf = 1; - f_abr_vc->f_cdf = ((7 - srv_p->cdf) << 12 | adtf) & 0xfff; - f_abr_vc->f_mcr = cellrate_to_float(srv_p->mcr); - f_abr_vc->f_acr = f_abr_vc->f_icr; - f_abr_vc->f_status = 0x0042; - break; - case 0: /* RFRED initialization */ - ptr16 = (u_short *)(dev->reass_ram + REASS_TABLE*dev->memSize); - *(ptr16 + vcc->vci) = NO_AAL5_PKT | REASS_ABR; - r_abr_vc = (r_vc_abr_entry*)(dev->reass_ram+ABR_VC_TABLE*dev->memSize); - r_abr_vc += vcc->vci; - r_abr_vc->r_status_rdf = (15 - srv_p->rdf) & 0x000f; - air = srv_p->pcr << (15 - srv_p->rif); - if (air == 0) air = 1; - r_abr_vc->r_air = cellrate_to_float(air); - dev->testTable[vcc->vci]->vc_status = VC_ACTIVE | VC_ABR; - dev->sum_mcr += srv_p->mcr; - dev->n_abr++; - break; - default: - break; - } - return 0; -} -static int ia_cbr_setup (IADEV *dev, struct atm_vcc *vcc) { - u32 rateLow=0, rateHigh, rate; - int entries; - struct ia_vcc *ia_vcc; - - int idealSlot =0, testSlot, toBeAssigned, inc; - u32 spacing; - u16 *SchedTbl, *TstSchedTbl; - u16 cbrVC, vcIndex; - u32 fracSlot = 0; - u32 sp_mod = 0; - u32 sp_mod2 = 0; - - /* IpAdjustTrafficParams */ - if (vcc->qos.txtp.max_pcr <= 0) { - IF_ERR(printk("PCR for CBR not defined\n");) - return -1; - } - rate = vcc->qos.txtp.max_pcr; - entries = rate / dev->Granularity; - IF_CBR(printk("CBR: CBR entries=0x%x for rate=0x%x & Gran=0x%x\n", - entries, rate, dev->Granularity);) - if (entries < 1) - IF_CBR(printk("CBR: Bandwidth smaller than granularity of CBR table\n");) - rateLow = entries * dev->Granularity; - rateHigh = (entries + 1) * dev->Granularity; - if (3*(rate - rateLow) > (rateHigh - rate)) - entries++; - if (entries > dev->CbrRemEntries) { - IF_CBR(printk("CBR: Not enough bandwidth to support this PCR.\n");) - IF_CBR(printk("Entries = 0x%x, CbrRemEntries = 0x%x.\n", - entries, dev->CbrRemEntries);) - return -EBUSY; - } - - ia_vcc = INPH_IA_VCC(vcc); - ia_vcc->NumCbrEntry = entries; - dev->sum_mcr += entries * dev->Granularity; - /* IaFFrednInsertCbrSched */ - // Starting at an arbitrary location, place the entries into the table - // as smoothly as possible - cbrVC = 0; - spacing = dev->CbrTotEntries / entries; - sp_mod = dev->CbrTotEntries % entries; // get modulo - toBeAssigned = entries; - fracSlot = 0; - vcIndex = vcc->vci; - IF_CBR(printk("Vci=0x%x,Spacing=0x%x,Sp_mod=0x%x\n",vcIndex,spacing,sp_mod);) - while (toBeAssigned) - { - // If this is the first time, start the table loading for this connection - // as close to entryPoint as possible. - if (toBeAssigned == entries) - { - idealSlot = dev->CbrEntryPt; - dev->CbrEntryPt += 2; // Adding 2 helps to prevent clumping - if (dev->CbrEntryPt >= dev->CbrTotEntries) - dev->CbrEntryPt -= dev->CbrTotEntries;// Wrap if necessary - } else { - idealSlot += (u32)(spacing + fracSlot); // Point to the next location - // in the table that would be smoothest - fracSlot = ((sp_mod + sp_mod2) / entries); // get new integer part - sp_mod2 = ((sp_mod + sp_mod2) % entries); // calc new fractional part - } - if (idealSlot >= (int)dev->CbrTotEntries) - idealSlot -= dev->CbrTotEntries; - // Continuously check around this ideal value until a null - // location is encountered. - SchedTbl = (u16*)(dev->seg_ram+CBR_SCHED_TABLE*dev->memSize); - inc = 0; - testSlot = idealSlot; - TstSchedTbl = (u16*)(SchedTbl+testSlot); //set index and read in value - IF_CBR(printk("CBR Testslot 0x%x AT Location 0x%p, NumToAssign=%d\n", - testSlot, TstSchedTbl,toBeAssigned);) - memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); - while (cbrVC) // If another VC at this location, we have to keep looking - { - inc++; - testSlot = idealSlot - inc; - if (testSlot < 0) { // Wrap if necessary - testSlot += dev->CbrTotEntries; - IF_CBR(printk("Testslot Wrap. STable Start=0x%p,Testslot=%d\n", - SchedTbl,testSlot);) - } - TstSchedTbl = (u16 *)(SchedTbl + testSlot); // set table index - memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); - if (!cbrVC) - break; - testSlot = idealSlot + inc; - if (testSlot >= (int)dev->CbrTotEntries) { // Wrap if necessary - testSlot -= dev->CbrTotEntries; - IF_CBR(printk("TotCbrEntries=%d",dev->CbrTotEntries);) - IF_CBR(printk(" Testslot=0x%x ToBeAssgned=%d\n", - testSlot, toBeAssigned);) - } - // set table index and read in value - TstSchedTbl = (u16*)(SchedTbl + testSlot); - IF_CBR(printk("Reading CBR Tbl from 0x%p, CbrVal=0x%x Iteration %d\n", - TstSchedTbl,cbrVC,inc);) - memcpy((caddr_t)&cbrVC,(caddr_t)TstSchedTbl,sizeof(cbrVC)); - } /* while */ - // Move this VCI number into this location of the CBR Sched table. - memcpy((caddr_t)TstSchedTbl, (caddr_t)&vcIndex, sizeof(*TstSchedTbl)); - dev->CbrRemEntries--; - toBeAssigned--; - } /* while */ - - /* IaFFrednCbrEnable */ - dev->NumEnabledCBR++; - if (dev->NumEnabledCBR == 1) { - writew((CBR_EN | UBR_EN | ABR_EN | (0x23 << 2)), dev->seg_reg+STPARMS); - IF_CBR(printk("CBR is enabled\n");) - } - return 0; -} -static void ia_cbrVc_close (struct atm_vcc *vcc) { - IADEV *iadev; - u16 *SchedTbl, NullVci = 0; - u32 i, NumFound; - - iadev = INPH_IA_DEV(vcc->dev); - iadev->NumEnabledCBR--; - SchedTbl = (u16*)(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize); - if (iadev->NumEnabledCBR == 0) { - writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); - IF_CBR (printk("CBR support disabled\n");) - } - NumFound = 0; - for (i=0; i < iadev->CbrTotEntries; i++) - { - if (*SchedTbl == vcc->vci) { - iadev->CbrRemEntries++; - *SchedTbl = NullVci; - IF_CBR(NumFound++;) - } - SchedTbl++; - } - IF_CBR(printk("Exit ia_cbrVc_close, NumRemoved=%d\n",NumFound);) -} - -static int ia_avail_descs(IADEV *iadev) { - int tmp = 0; - ia_hack_tcq(iadev); - if (iadev->host_tcq_wr >= iadev->ffL.tcq_rd) - tmp = (iadev->host_tcq_wr - iadev->ffL.tcq_rd) / 2; - else - tmp = (iadev->ffL.tcq_ed - iadev->ffL.tcq_rd + 2 + iadev->host_tcq_wr - - iadev->ffL.tcq_st) / 2; - return tmp; -} - -static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb); - -static int ia_que_tx (IADEV *iadev) { - struct sk_buff *skb; - int num_desc; - struct atm_vcc *vcc; - num_desc = ia_avail_descs(iadev); - - while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) { - if (!(vcc = ATM_SKB(skb)->vcc)) { - dev_kfree_skb_any(skb); - printk("ia_que_tx: Null vcc\n"); - break; - } - if (!test_bit(ATM_VF_READY,&vcc->flags)) { - dev_kfree_skb_any(skb); - printk("Free the SKB on closed vci %d \n", vcc->vci); - break; - } - if (ia_pkt_tx (vcc, skb)) { - skb_queue_head(&iadev->tx_backlog, skb); - } - num_desc--; - } - return 0; -} - -static void ia_tx_poll (IADEV *iadev) { - struct atm_vcc *vcc = NULL; - struct sk_buff *skb = NULL, *skb1 = NULL; - struct ia_vcc *iavcc; - IARTN_Q * rtne; - - ia_hack_tcq(iadev); - while ( (rtne = ia_deque_rtn_q(&iadev->tx_return_q))) { - skb = rtne->data.txskb; - if (!skb) { - printk("ia_tx_poll: skb is null\n"); - goto out; - } - vcc = ATM_SKB(skb)->vcc; - if (!vcc) { - printk("ia_tx_poll: vcc is null\n"); - dev_kfree_skb_any(skb); - goto out; - } - - iavcc = INPH_IA_VCC(vcc); - if (!iavcc) { - printk("ia_tx_poll: iavcc is null\n"); - dev_kfree_skb_any(skb); - goto out; - } - - skb1 = skb_dequeue(&iavcc->txing_skb); - while (skb1 && (skb1 != skb)) { - if (!(IA_SKB_STATE(skb1) & IA_TX_DONE)) { - printk("IA_tx_intr: Vci %d lost pkt!!!\n", vcc->vci); - } - IF_ERR(printk("Release the SKB not match\n");) - if ((vcc->pop) && (skb1->len != 0)) - { - vcc->pop(vcc, skb1); - IF_EVENT(printk("Transmit Done - skb 0x%lx return\n", - (long)skb1);) - } - else - dev_kfree_skb_any(skb1); - skb1 = skb_dequeue(&iavcc->txing_skb); - } - if (!skb1) { - IF_EVENT(printk("IA: Vci %d - skb not found requeued\n",vcc->vci);) - ia_enque_head_rtn_q (&iadev->tx_return_q, rtne); - break; - } - if ((vcc->pop) && (skb->len != 0)) - { - vcc->pop(vcc, skb); - IF_EVENT(printk("Tx Done - skb 0x%lx return\n",(long)skb);) - } - else - dev_kfree_skb_any(skb); - kfree(rtne); - } - ia_que_tx(iadev); -out: - return; -} -#if 0 -static void ia_eeprom_put (IADEV *iadev, u32 addr, u_short val) -{ - u32 t; - int i; - /* - * Issue a command to enable writes to the NOVRAM - */ - NVRAM_CMD (EXTEND + EWEN); - NVRAM_CLR_CE; - /* - * issue the write command - */ - NVRAM_CMD(IAWRITE + addr); - /* - * Send the data, starting with D15, then D14, and so on for 16 bits - */ - for (i=15; i>=0; i--) { - NVRAM_CLKOUT (val & 0x8000); - val <<= 1; - } - NVRAM_CLR_CE; - CFG_OR(NVCE); - t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); - while (!(t & NVDO)) - t = readl(iadev->reg+IPHASE5575_EEPROM_ACCESS); - - NVRAM_CLR_CE; - /* - * disable writes again - */ - NVRAM_CMD(EXTEND + EWDS) - NVRAM_CLR_CE; - CFG_AND(~NVDI); -} -#endif - -static u16 ia_eeprom_get (IADEV *iadev, u32 addr) -{ - u_short val; - u32 t; - int i; - /* - * Read the first bit that was clocked with the falling edge of - * the last command data clock - */ - NVRAM_CMD(IAREAD + addr); - /* - * Now read the rest of the bits, the next bit read is D14, then D13, - * and so on. - */ - val = 0; - for (i=15; i>=0; i--) { - NVRAM_CLKIN(t); - val |= (t << i); - } - NVRAM_CLR_CE; - CFG_AND(~NVDI); - return val; -} - -static void ia_hw_type(IADEV *iadev) { - u_short memType = ia_eeprom_get(iadev, 25); - iadev->memType = memType; - if ((memType & MEM_SIZE_MASK) == MEM_SIZE_1M) { - iadev->num_tx_desc = IA_TX_BUF; - iadev->tx_buf_sz = IA_TX_BUF_SZ; - iadev->num_rx_desc = IA_RX_BUF; - iadev->rx_buf_sz = IA_RX_BUF_SZ; - } else if ((memType & MEM_SIZE_MASK) == MEM_SIZE_512K) { - if (IA_TX_BUF == DFL_TX_BUFFERS) - iadev->num_tx_desc = IA_TX_BUF / 2; - else - iadev->num_tx_desc = IA_TX_BUF; - iadev->tx_buf_sz = IA_TX_BUF_SZ; - if (IA_RX_BUF == DFL_RX_BUFFERS) - iadev->num_rx_desc = IA_RX_BUF / 2; - else - iadev->num_rx_desc = IA_RX_BUF; - iadev->rx_buf_sz = IA_RX_BUF_SZ; - } - else { - if (IA_TX_BUF == DFL_TX_BUFFERS) - iadev->num_tx_desc = IA_TX_BUF / 8; - else - iadev->num_tx_desc = IA_TX_BUF; - iadev->tx_buf_sz = IA_TX_BUF_SZ; - if (IA_RX_BUF == DFL_RX_BUFFERS) - iadev->num_rx_desc = IA_RX_BUF / 8; - else - iadev->num_rx_desc = IA_RX_BUF; - iadev->rx_buf_sz = IA_RX_BUF_SZ; - } - iadev->rx_pkt_ram = TX_PACKET_RAM + (iadev->num_tx_desc * iadev->tx_buf_sz); - IF_INIT(printk("BUF: tx=%d,sz=%d rx=%d sz= %d rx_pkt_ram=%d\n", - iadev->num_tx_desc, iadev->tx_buf_sz, iadev->num_rx_desc, - iadev->rx_buf_sz, iadev->rx_pkt_ram);) - -#if 0 - if ((memType & FE_MASK) == FE_SINGLE_MODE) { - iadev->phy_type = PHY_OC3C_S; - else if ((memType & FE_MASK) == FE_UTP_OPTION) - iadev->phy_type = PHY_UTP155; - else - iadev->phy_type = PHY_OC3C_M; -#endif - - iadev->phy_type = memType & FE_MASK; - IF_INIT(printk("memType = 0x%x iadev->phy_type = 0x%x\n", - memType,iadev->phy_type);) - if (iadev->phy_type == FE_25MBIT_PHY) - iadev->LineRate = (u32)(((25600000/8)*26)/(27*53)); - else if (iadev->phy_type == FE_DS3_PHY) - iadev->LineRate = (u32)(((44736000/8)*26)/(27*53)); - else if (iadev->phy_type == FE_E3_PHY) - iadev->LineRate = (u32)(((34368000/8)*26)/(27*53)); - else - iadev->LineRate = (u32)(ATM_OC3_PCR); - IF_INIT(printk("iadev->LineRate = %d \n", iadev->LineRate);) - -} - -static u32 ia_phy_read32(struct iadev_priv *ia, unsigned int reg) -{ - return readl(ia->phy + (reg >> 2)); -} - -static void ia_phy_write32(struct iadev_priv *ia, unsigned int reg, u32 val) -{ - writel(val, ia->phy + (reg >> 2)); -} - -static void ia_frontend_intr(struct iadev_priv *iadev) -{ - u32 status; - - if (iadev->phy_type & FE_25MBIT_PHY) { - status = ia_phy_read32(iadev, MB25_INTR_STATUS); - iadev->carrier_detect = (status & MB25_IS_GSB) ? 1 : 0; - } else if (iadev->phy_type & FE_DS3_PHY) { - ia_phy_read32(iadev, SUNI_DS3_FRM_INTR_STAT); - status = ia_phy_read32(iadev, SUNI_DS3_FRM_STAT); - iadev->carrier_detect = (status & SUNI_DS3_LOSV) ? 0 : 1; - } else if (iadev->phy_type & FE_E3_PHY) { - ia_phy_read32(iadev, SUNI_E3_FRM_MAINT_INTR_IND); - status = ia_phy_read32(iadev, SUNI_E3_FRM_FRAM_INTR_IND_STAT); - iadev->carrier_detect = (status & SUNI_E3_LOS) ? 0 : 1; - } else { - status = ia_phy_read32(iadev, SUNI_RSOP_STATUS); - iadev->carrier_detect = (status & SUNI_LOSV) ? 0 : 1; - } - - printk(KERN_INFO "IA: SUNI carrier %s\n", - iadev->carrier_detect ? "detected" : "lost signal"); -} - -static void ia_mb25_init(struct iadev_priv *iadev) -{ -#if 0 - mb25->mb25_master_ctrl = MB25_MC_DRIC | MB25_MC_DREC | MB25_MC_ENABLED; -#endif - ia_phy_write32(iadev, MB25_MASTER_CTRL, MB25_MC_DRIC | MB25_MC_DREC); - ia_phy_write32(iadev, MB25_DIAG_CONTROL, 0); - - iadev->carrier_detect = - (ia_phy_read32(iadev, MB25_INTR_STATUS) & MB25_IS_GSB) ? 1 : 0; -} - -struct ia_reg { - u16 reg; - u16 val; -}; - -static void ia_phy_write(struct iadev_priv *iadev, - const struct ia_reg *regs, int len) -{ - while (len--) { - ia_phy_write32(iadev, regs->reg, regs->val); - regs++; - } -} - -static void ia_suni_pm7345_init_ds3(struct iadev_priv *iadev) -{ - static const struct ia_reg suni_ds3_init[] = { - { SUNI_DS3_FRM_INTR_ENBL, 0x17 }, - { SUNI_DS3_FRM_CFG, 0x01 }, - { SUNI_DS3_TRAN_CFG, 0x01 }, - { SUNI_CONFIG, 0 }, - { SUNI_SPLR_CFG, 0 }, - { SUNI_SPLT_CFG, 0 } - }; - u32 status; - - status = ia_phy_read32(iadev, SUNI_DS3_FRM_STAT); - iadev->carrier_detect = (status & SUNI_DS3_LOSV) ? 0 : 1; - - ia_phy_write(iadev, suni_ds3_init, ARRAY_SIZE(suni_ds3_init)); -} - -static void ia_suni_pm7345_init_e3(struct iadev_priv *iadev) -{ - static const struct ia_reg suni_e3_init[] = { - { SUNI_E3_FRM_FRAM_OPTIONS, 0x04 }, - { SUNI_E3_FRM_MAINT_OPTIONS, 0x20 }, - { SUNI_E3_FRM_FRAM_INTR_ENBL, 0x1d }, - { SUNI_E3_FRM_MAINT_INTR_ENBL, 0x30 }, - { SUNI_E3_TRAN_STAT_DIAG_OPTIONS, 0 }, - { SUNI_E3_TRAN_FRAM_OPTIONS, 0x01 }, - { SUNI_CONFIG, SUNI_PM7345_E3ENBL }, - { SUNI_SPLR_CFG, 0x41 }, - { SUNI_SPLT_CFG, 0x41 } - }; - u32 status; - - status = ia_phy_read32(iadev, SUNI_E3_FRM_FRAM_INTR_IND_STAT); - iadev->carrier_detect = (status & SUNI_E3_LOS) ? 0 : 1; - ia_phy_write(iadev, suni_e3_init, ARRAY_SIZE(suni_e3_init)); -} - -static void ia_suni_pm7345_init(struct iadev_priv *iadev) -{ - static const struct ia_reg suni_init[] = { - /* Enable RSOP loss of signal interrupt. */ - { SUNI_INTR_ENBL, 0x28 }, - /* Clear error counters. */ - { SUNI_ID_RESET, 0 }, - /* Clear "PMCTST" in master test register. */ - { SUNI_MASTER_TEST, 0 }, - - { SUNI_RXCP_CTRL, 0x2c }, - { SUNI_RXCP_FCTRL, 0x81 }, - - { SUNI_RXCP_IDLE_PAT_H1, 0 }, - { SUNI_RXCP_IDLE_PAT_H2, 0 }, - { SUNI_RXCP_IDLE_PAT_H3, 0 }, - { SUNI_RXCP_IDLE_PAT_H4, 0x01 }, - - { SUNI_RXCP_IDLE_MASK_H1, 0xff }, - { SUNI_RXCP_IDLE_MASK_H2, 0xff }, - { SUNI_RXCP_IDLE_MASK_H3, 0xff }, - { SUNI_RXCP_IDLE_MASK_H4, 0xfe }, - - { SUNI_RXCP_CELL_PAT_H1, 0 }, - { SUNI_RXCP_CELL_PAT_H2, 0 }, - { SUNI_RXCP_CELL_PAT_H3, 0 }, - { SUNI_RXCP_CELL_PAT_H4, 0x01 }, - - { SUNI_RXCP_CELL_MASK_H1, 0xff }, - { SUNI_RXCP_CELL_MASK_H2, 0xff }, - { SUNI_RXCP_CELL_MASK_H3, 0xff }, - { SUNI_RXCP_CELL_MASK_H4, 0xff }, - - { SUNI_TXCP_CTRL, 0xa4 }, - { SUNI_TXCP_INTR_EN_STS, 0x10 }, - { SUNI_TXCP_IDLE_PAT_H5, 0x55 } - }; - - if (iadev->phy_type & FE_DS3_PHY) - ia_suni_pm7345_init_ds3(iadev); - else - ia_suni_pm7345_init_e3(iadev); - - ia_phy_write(iadev, suni_init, ARRAY_SIZE(suni_init)); - - ia_phy_write32(iadev, SUNI_CONFIG, ia_phy_read32(iadev, SUNI_CONFIG) & - ~(SUNI_PM7345_LLB | SUNI_PM7345_CLB | - SUNI_PM7345_DLB | SUNI_PM7345_PLB)); -#ifdef __SNMP__ - suni_pm7345->suni_rxcp_intr_en_sts |= SUNI_OOCDE; -#endif /* __SNMP__ */ - return; -} - - -/***************************** IA_LIB END *****************************/ - -#ifdef CONFIG_ATM_IA_DEBUG -static int tcnter = 0; -static void xdump( u_char* cp, int length, char* prefix ) -{ - int col, count; - u_char prntBuf[120]; - u_char* pBuf = prntBuf; - count = 0; - while(count < length){ - pBuf += sprintf( pBuf, "%s", prefix ); - for(col = 0;count + col < length && col < 16; col++){ - if (col != 0 && (col % 4) == 0) - pBuf += sprintf( pBuf, " " ); - pBuf += sprintf( pBuf, "%02X ", cp[count + col] ); - } - while(col++ < 16){ /* pad end of buffer with blanks */ - if ((col % 4) == 0) - sprintf( pBuf, " " ); - pBuf += sprintf( pBuf, " " ); - } - pBuf += sprintf( pBuf, " " ); - for(col = 0;count + col < length && col < 16; col++){ - u_char c = cp[count + col]; - - if (isascii(c) && isprint(c)) - pBuf += sprintf(pBuf, "%c", c); - else - pBuf += sprintf(pBuf, "."); - } - printk("%s\n", prntBuf); - count += col; - pBuf = prntBuf; - } - -} /* close xdump(... */ -#endif /* CONFIG_ATM_IA_DEBUG */ - - -static struct atm_dev *ia_boards = NULL; - -#define ACTUAL_RAM_BASE \ - RAM_BASE*((iadev->mem)/(128 * 1024)) -#define ACTUAL_SEG_RAM_BASE \ - IPHASE5575_FRAG_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) -#define ACTUAL_REASS_RAM_BASE \ - IPHASE5575_REASS_CONTROL_RAM_BASE*((iadev->mem)/(128 * 1024)) - - -/*-- some utilities and memory allocation stuff will come here -------------*/ - -static void desc_dbg(IADEV *iadev) { - - u_short tcq_wr_ptr, tcq_st_ptr, tcq_ed_ptr; - u32 i; - void __iomem *tmp; - // regval = readl((u32)ia_cmds->maddr); - tcq_wr_ptr = readw(iadev->seg_reg+TCQ_WR_PTR); - printk("B_tcq_wr = 0x%x desc = %d last desc = %d\n", - tcq_wr_ptr, readw(iadev->seg_ram+tcq_wr_ptr), - readw(iadev->seg_ram+tcq_wr_ptr-2)); - printk(" host_tcq_wr = 0x%x host_tcq_rd = 0x%x \n", iadev->host_tcq_wr, - iadev->ffL.tcq_rd); - tcq_st_ptr = readw(iadev->seg_reg+TCQ_ST_ADR); - tcq_ed_ptr = readw(iadev->seg_reg+TCQ_ED_ADR); - printk("tcq_st_ptr = 0x%x tcq_ed_ptr = 0x%x \n", tcq_st_ptr, tcq_ed_ptr); - i = 0; - while (tcq_st_ptr != tcq_ed_ptr) { - tmp = iadev->seg_ram+tcq_st_ptr; - printk("TCQ slot %d desc = %d Addr = %p\n", i++, readw(tmp), tmp); - tcq_st_ptr += 2; - } - for(i=0; i num_tx_desc; i++) - printk("Desc_tbl[%d] = %d \n", i, iadev->desc_tbl[i].timestamp); -} - - -/*----------------------------- Receiving side stuff --------------------------*/ - -static void rx_excp_rcvd(struct atm_dev *dev) -{ -#if 0 /* closing the receiving size will cause too many excp int */ - IADEV *iadev; - u_short state; - u_short excpq_rd_ptr; - //u_short *ptr; - int vci, error = 1; - iadev = INPH_IA_DEV(dev); - state = readl(iadev->reass_reg + STATE_REG) & 0xffff; - while((state & EXCPQ_EMPTY) != EXCPQ_EMPTY) - { printk("state = %x \n", state); - excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_RD_PTR) & 0xffff; - printk("state = %x excpq_rd_ptr = %x \n", state, excpq_rd_ptr); - if (excpq_rd_ptr == *(u16*)(iadev->reass_reg + EXCP_Q_WR_PTR)) - IF_ERR(printk("excpq_rd_ptr is wrong!!!\n");) - // TODO: update exception stat - vci = readw(iadev->reass_ram+excpq_rd_ptr); - error = readw(iadev->reass_ram+excpq_rd_ptr+2) & 0x0007; - // pwang_test - excpq_rd_ptr += 4; - if (excpq_rd_ptr > (readw(iadev->reass_reg + EXCP_Q_ED_ADR)& 0xffff)) - excpq_rd_ptr = readw(iadev->reass_reg + EXCP_Q_ST_ADR)& 0xffff; - writew( excpq_rd_ptr, iadev->reass_reg + EXCP_Q_RD_PTR); - state = readl(iadev->reass_reg + STATE_REG) & 0xffff; - } -#endif -} - -static void free_desc(struct atm_dev *dev, int desc) -{ - IADEV *iadev; - iadev = INPH_IA_DEV(dev); - writew(desc, iadev->reass_ram+iadev->rfL.fdq_wr); - iadev->rfL.fdq_wr +=2; - if (iadev->rfL.fdq_wr > iadev->rfL.fdq_ed) - iadev->rfL.fdq_wr = iadev->rfL.fdq_st; - writew(iadev->rfL.fdq_wr, iadev->reass_reg+FREEQ_WR_PTR); -} - - -static int rx_pkt(struct atm_dev *dev) -{ - IADEV *iadev; - struct atm_vcc *vcc; - unsigned short status; - struct rx_buf_desc __iomem *buf_desc_ptr; - int desc; - struct dle* wr_ptr; - int len; - struct sk_buff *skb; - u_int buf_addr, dma_addr; - - iadev = INPH_IA_DEV(dev); - if (iadev->rfL.pcq_rd == (readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff)) - { - printk(KERN_ERR DEV_LABEL "(itf %d) Receive queue empty\n", dev->number); - return -EINVAL; - } - /* mask 1st 3 bits to get the actual descno. */ - desc = readw(iadev->reass_ram+iadev->rfL.pcq_rd) & 0x1fff; - IF_RX(printk("reass_ram = %p iadev->rfL.pcq_rd = 0x%x desc = %d\n", - iadev->reass_ram, iadev->rfL.pcq_rd, desc); - printk(" pcq_wr_ptr = 0x%x\n", - readw(iadev->reass_reg+PCQ_WR_PTR)&0xffff);) - /* update the read pointer - maybe we shud do this in the end*/ - if ( iadev->rfL.pcq_rd== iadev->rfL.pcq_ed) - iadev->rfL.pcq_rd = iadev->rfL.pcq_st; - else - iadev->rfL.pcq_rd += 2; - writew(iadev->rfL.pcq_rd, iadev->reass_reg+PCQ_RD_PTR); - - /* get the buffer desc entry. - update stuff. - doesn't seem to be any update necessary - */ - buf_desc_ptr = iadev->RX_DESC_BASE_ADDR; - /* make the ptr point to the corresponding buffer desc entry */ - buf_desc_ptr += desc; - if (!desc || (desc > iadev->num_rx_desc) || - ((buf_desc_ptr->vc_index & 0xffff) >= iadev->num_vc)) { - free_desc(dev, desc); - IF_ERR(printk("IA: bad descriptor desc = %d \n", desc);) - return -1; - } - vcc = iadev->rx_open[buf_desc_ptr->vc_index & 0xffff]; - if (!vcc) - { - free_desc(dev, desc); - printk("IA: null vcc, drop PDU\n"); - return -1; - } - - - /* might want to check the status bits for errors */ - status = (u_short) (buf_desc_ptr->desc_mode); - if (status & (RX_CER | RX_PTE | RX_OFL)) - { - atomic_inc(&vcc->stats->rx_err); - IF_ERR(printk("IA: bad packet, dropping it");) - if (status & RX_CER) { - IF_ERR(printk(" cause: packet CRC error\n");) - } - else if (status & RX_PTE) { - IF_ERR(printk(" cause: packet time out\n");) - } - else { - IF_ERR(printk(" cause: buffer overflow\n");) - } - goto out_free_desc; - } - - /* - build DLE. - */ - - buf_addr = (buf_desc_ptr->buf_start_hi << 16) | buf_desc_ptr->buf_start_lo; - dma_addr = (buf_desc_ptr->dma_start_hi << 16) | buf_desc_ptr->dma_start_lo; - len = dma_addr - buf_addr; - if (len > iadev->rx_buf_sz) { - printk("Over %d bytes sdu received, dropped!!!\n", iadev->rx_buf_sz); - atomic_inc(&vcc->stats->rx_err); - goto out_free_desc; - } - - if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) { - if (vcc->vci < 32) - printk("Drop control packets\n"); - goto out_free_desc; - } - skb_put(skb,len); - // pwang_test - ATM_SKB(skb)->vcc = vcc; - ATM_DESC(skb) = desc; - skb_queue_tail(&iadev->rx_dma_q, skb); - - /* Build the DLE structure */ - wr_ptr = iadev->rx_dle_q.write; - wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data, - len, DMA_FROM_DEVICE); - wr_ptr->local_pkt_addr = buf_addr; - wr_ptr->bytes = len; /* We don't know this do we ?? */ - wr_ptr->mode = DMA_INT_ENABLE; - - /* shud take care of wrap around here too. */ - if(++wr_ptr == iadev->rx_dle_q.end) - wr_ptr = iadev->rx_dle_q.start; - iadev->rx_dle_q.write = wr_ptr; - udelay(1); - /* Increment transaction counter */ - writel(1, iadev->dma+IPHASE5575_RX_COUNTER); -out: return 0; -out_free_desc: - free_desc(dev, desc); - goto out; -} - -static void rx_intr(struct atm_dev *dev) -{ - IADEV *iadev; - u_short status; - u_short state, i; - - iadev = INPH_IA_DEV(dev); - status = readl(iadev->reass_reg+REASS_INTR_STATUS_REG) & 0xffff; - IF_EVENT(printk("rx_intr: status = 0x%x\n", status);) - if (status & RX_PKT_RCVD) - { - /* do something */ - /* Basically recvd an interrupt for receiving a packet. - A descriptor would have been written to the packet complete - queue. Get all the descriptors and set up dma to move the - packets till the packet complete queue is empty.. - */ - state = readl(iadev->reass_reg + STATE_REG) & 0xffff; - IF_EVENT(printk("Rx intr status: RX_PKT_RCVD %08x\n", status);) - while(!(state & PCQ_EMPTY)) - { - rx_pkt(dev); - state = readl(iadev->reass_reg + STATE_REG) & 0xffff; - } - iadev->rxing = 1; - } - if (status & RX_FREEQ_EMPT) - { - if (iadev->rxing) { - iadev->rx_tmp_cnt = iadev->rx_pkt_cnt; - iadev->rx_tmp_jif = jiffies; - iadev->rxing = 0; - } - else if ((time_after(jiffies, iadev->rx_tmp_jif + 50)) && - ((iadev->rx_pkt_cnt - iadev->rx_tmp_cnt) == 0)) { - for (i = 1; i <= iadev->num_rx_desc; i++) - free_desc(dev, i); -printk("Test logic RUN!!!!\n"); - writew( ~(RX_FREEQ_EMPT|RX_EXCP_RCVD),iadev->reass_reg+REASS_MASK_REG); - iadev->rxing = 1; - } - IF_EVENT(printk("Rx intr status: RX_FREEQ_EMPT %08x\n", status);) - } - - if (status & RX_EXCP_RCVD) - { - /* probably need to handle the exception queue also. */ - IF_EVENT(printk("Rx intr status: RX_EXCP_RCVD %08x\n", status);) - rx_excp_rcvd(dev); - } - - - if (status & RX_RAW_RCVD) - { - /* need to handle the raw incoming cells. This deepnds on - whether we have programmed to receive the raw cells or not. - Else ignore. */ - IF_EVENT(printk("Rx intr status: RX_RAW_RCVD %08x\n", status);) - } -} - - -static void rx_dle_intr(struct atm_dev *dev) -{ - IADEV *iadev; - struct atm_vcc *vcc; - struct sk_buff *skb; - int desc; - u_short state; - struct dle *dle, *cur_dle; - u_int dle_lp; - int len; - iadev = INPH_IA_DEV(dev); - - /* free all the dles done, that is just update our own dle read pointer - - do we really need to do this. Think not. */ - /* DMA is done, just get all the recevie buffers from the rx dma queue - and push them up to the higher layer protocol. Also free the desc - associated with the buffer. */ - dle = iadev->rx_dle_q.read; - dle_lp = readl(iadev->dma+IPHASE5575_RX_LIST_ADDR) & (sizeof(struct dle)*DLE_ENTRIES - 1); - cur_dle = (struct dle*)(iadev->rx_dle_q.start + (dle_lp >> 4)); - while(dle != cur_dle) - { - /* free the DMAed skb */ - skb = skb_dequeue(&iadev->rx_dma_q); - if (!skb) - goto INCR_DLE; - desc = ATM_DESC(skb); - free_desc(dev, desc); - - if (!(len = skb->len)) - { - printk("rx_dle_intr: skb len 0\n"); - dev_kfree_skb_any(skb); - } - else - { - struct cpcs_trailer *trailer; - u_short length; - struct ia_vcc *ia_vcc; - - dma_unmap_single(&iadev->pci->dev, iadev->rx_dle_q.write->sys_pkt_addr, - len, DMA_FROM_DEVICE); - /* no VCC related housekeeping done as yet. lets see */ - vcc = ATM_SKB(skb)->vcc; - if (!vcc) { - printk("IA: null vcc\n"); - dev_kfree_skb_any(skb); - goto INCR_DLE; - } - ia_vcc = INPH_IA_VCC(vcc); - if (ia_vcc == NULL) - { - atomic_inc(&vcc->stats->rx_err); - atm_return(vcc, skb->truesize); - dev_kfree_skb_any(skb); - goto INCR_DLE; - } - // get real pkt length pwang_test - trailer = (struct cpcs_trailer*)((u_char *)skb->data + - skb->len - sizeof(*trailer)); - length = swap_byte_order(trailer->length); - if ((length > iadev->rx_buf_sz) || (length > - (skb->len - sizeof(struct cpcs_trailer)))) - { - atomic_inc(&vcc->stats->rx_err); - IF_ERR(printk("rx_dle_intr: Bad AAL5 trailer %d (skb len %d)", - length, skb->len);) - atm_return(vcc, skb->truesize); - dev_kfree_skb_any(skb); - goto INCR_DLE; - } - skb_trim(skb, length); - - /* Display the packet */ - IF_RXPKT(printk("\nDmad Recvd data: len = %d \n", skb->len); - xdump(skb->data, skb->len, "RX: "); - printk("\n");) - - IF_RX(printk("rx_dle_intr: skb push");) - vcc->push(vcc,skb); - atomic_inc(&vcc->stats->rx); - iadev->rx_pkt_cnt++; - } -INCR_DLE: - if (++dle == iadev->rx_dle_q.end) - dle = iadev->rx_dle_q.start; - } - iadev->rx_dle_q.read = dle; - - /* if the interrupts are masked because there were no free desc available, - unmask them now. */ - if (!iadev->rxing) { - state = readl(iadev->reass_reg + STATE_REG) & 0xffff; - if (!(state & FREEQ_EMPTY)) { - state = readl(iadev->reass_reg + REASS_MASK_REG) & 0xffff; - writel(state & ~(RX_FREEQ_EMPT |/* RX_EXCP_RCVD |*/ RX_PKT_RCVD), - iadev->reass_reg+REASS_MASK_REG); - iadev->rxing++; - } - } -} - - -static int open_rx(struct atm_vcc *vcc) -{ - IADEV *iadev; - u_short __iomem *vc_table; - u_short __iomem *reass_ptr; - IF_EVENT(printk("iadev: open_rx %d.%d\n", vcc->vpi, vcc->vci);) - - if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0; - iadev = INPH_IA_DEV(vcc->dev); - if (vcc->qos.rxtp.traffic_class == ATM_ABR) { - if (iadev->phy_type & FE_25MBIT_PHY) { - printk("IA: ABR not support\n"); - return -EINVAL; - } - } - /* Make only this VCI in the vc table valid and let all - others be invalid entries */ - vc_table = iadev->reass_ram+RX_VC_TABLE*iadev->memSize; - vc_table += vcc->vci; - /* mask the last 6 bits and OR it with 3 for 1K VCs */ - - *vc_table = vcc->vci << 6; - /* Also keep a list of open rx vcs so that we can attach them with - incoming PDUs later. */ - if ((vcc->qos.rxtp.traffic_class == ATM_ABR) || - (vcc->qos.txtp.traffic_class == ATM_ABR)) - { - srv_cls_param_t srv_p; - init_abr_vc(iadev, &srv_p); - ia_open_abr_vc(iadev, &srv_p, vcc, 0); - } - else { /* for UBR later may need to add CBR logic */ - reass_ptr = iadev->reass_ram+REASS_TABLE*iadev->memSize; - reass_ptr += vcc->vci; - *reass_ptr = NO_AAL5_PKT; - } - - if (iadev->rx_open[vcc->vci]) - printk(KERN_CRIT DEV_LABEL "(itf %d): VCI %d already open\n", - vcc->dev->number, vcc->vci); - iadev->rx_open[vcc->vci] = vcc; - return 0; -} - -static int rx_init(struct atm_dev *dev) -{ - IADEV *iadev; - struct rx_buf_desc __iomem *buf_desc_ptr; - unsigned long rx_pkt_start = 0; - void *dle_addr; - struct abr_vc_table *abr_vc_table; - u16 *vc_table; - u16 *reass_table; - int i,j, vcsize_sel; - u_short freeq_st_adr; - u_short *freeq_start; - - iadev = INPH_IA_DEV(dev); - // spin_lock_init(&iadev->rx_lock); - - /* Allocate 4k bytes - more aligned than needed (4k boundary) */ - dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, - &iadev->rx_dle_dma, GFP_KERNEL); - if (!dle_addr) { - printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); - goto err_out; - } - iadev->rx_dle_q.start = (struct dle *)dle_addr; - iadev->rx_dle_q.read = iadev->rx_dle_q.start; - iadev->rx_dle_q.write = iadev->rx_dle_q.start; - iadev->rx_dle_q.end = (struct dle*)((unsigned long)dle_addr+sizeof(struct dle)*DLE_ENTRIES); - /* the end of the dle q points to the entry after the last - DLE that can be used. */ - - /* write the upper 20 bits of the start address to rx list address register */ - /* We know this is 32bit bus addressed so the following is safe */ - writel(iadev->rx_dle_dma & 0xfffff000, - iadev->dma + IPHASE5575_RX_LIST_ADDR); - IF_INIT(printk("Tx Dle list addr: 0x%p value: 0x%0x\n", - iadev->dma+IPHASE5575_TX_LIST_ADDR, - readl(iadev->dma + IPHASE5575_TX_LIST_ADDR)); - printk("Rx Dle list addr: 0x%p value: 0x%0x\n", - iadev->dma+IPHASE5575_RX_LIST_ADDR, - readl(iadev->dma + IPHASE5575_RX_LIST_ADDR));) - - writew(0xffff, iadev->reass_reg+REASS_MASK_REG); - writew(0, iadev->reass_reg+MODE_REG); - writew(RESET_REASS, iadev->reass_reg+REASS_COMMAND_REG); - - /* Receive side control memory map - ------------------------------- - - Buffer descr 0x0000 (736 - 23K) - VP Table 0x5c00 (256 - 512) - Except q 0x5e00 (128 - 512) - Free buffer q 0x6000 (1K - 2K) - Packet comp q 0x6800 (1K - 2K) - Reass Table 0x7000 (1K - 2K) - VC Table 0x7800 (1K - 2K) - ABR VC Table 0x8000 (1K - 32K) - */ - - /* Base address for Buffer Descriptor Table */ - writew(RX_DESC_BASE >> 16, iadev->reass_reg+REASS_DESC_BASE); - /* Set the buffer size register */ - writew(iadev->rx_buf_sz, iadev->reass_reg+BUF_SIZE); - - /* Initialize each entry in the Buffer Descriptor Table */ - iadev->RX_DESC_BASE_ADDR = iadev->reass_ram+RX_DESC_BASE*iadev->memSize; - buf_desc_ptr = iadev->RX_DESC_BASE_ADDR; - memset_io(buf_desc_ptr, 0, sizeof(*buf_desc_ptr)); - buf_desc_ptr++; - rx_pkt_start = iadev->rx_pkt_ram; - for(i=1; i<=iadev->num_rx_desc; i++) - { - memset_io(buf_desc_ptr, 0, sizeof(*buf_desc_ptr)); - buf_desc_ptr->buf_start_hi = rx_pkt_start >> 16; - buf_desc_ptr->buf_start_lo = rx_pkt_start & 0x0000ffff; - buf_desc_ptr++; - rx_pkt_start += iadev->rx_buf_sz; - } - IF_INIT(printk("Rx Buffer desc ptr: 0x%p\n", buf_desc_ptr);) - i = FREE_BUF_DESC_Q*iadev->memSize; - writew(i >> 16, iadev->reass_reg+REASS_QUEUE_BASE); - writew(i, iadev->reass_reg+FREEQ_ST_ADR); - writew(i+iadev->num_rx_desc*sizeof(u_short), - iadev->reass_reg+FREEQ_ED_ADR); - writew(i, iadev->reass_reg+FREEQ_RD_PTR); - writew(i+iadev->num_rx_desc*sizeof(u_short), - iadev->reass_reg+FREEQ_WR_PTR); - /* Fill the FREEQ with all the free descriptors. */ - freeq_st_adr = readw(iadev->reass_reg+FREEQ_ST_ADR); - freeq_start = (u_short *)(iadev->reass_ram+freeq_st_adr); - for(i=1; i<=iadev->num_rx_desc; i++) - { - *freeq_start = (u_short)i; - freeq_start++; - } - IF_INIT(printk("freeq_start: 0x%p\n", freeq_start);) - /* Packet Complete Queue */ - i = (PKT_COMP_Q * iadev->memSize) & 0xffff; - writew(i, iadev->reass_reg+PCQ_ST_ADR); - writew(i+iadev->num_vc*sizeof(u_short), iadev->reass_reg+PCQ_ED_ADR); - writew(i, iadev->reass_reg+PCQ_RD_PTR); - writew(i, iadev->reass_reg+PCQ_WR_PTR); - - /* Exception Queue */ - i = (EXCEPTION_Q * iadev->memSize) & 0xffff; - writew(i, iadev->reass_reg+EXCP_Q_ST_ADR); - writew(i + NUM_RX_EXCP * sizeof(RX_ERROR_Q), - iadev->reass_reg+EXCP_Q_ED_ADR); - writew(i, iadev->reass_reg+EXCP_Q_RD_PTR); - writew(i, iadev->reass_reg+EXCP_Q_WR_PTR); - - /* Load local copy of FREEQ and PCQ ptrs */ - iadev->rfL.fdq_st = readw(iadev->reass_reg+FREEQ_ST_ADR) & 0xffff; - iadev->rfL.fdq_ed = readw(iadev->reass_reg+FREEQ_ED_ADR) & 0xffff ; - iadev->rfL.fdq_rd = readw(iadev->reass_reg+FREEQ_RD_PTR) & 0xffff; - iadev->rfL.fdq_wr = readw(iadev->reass_reg+FREEQ_WR_PTR) & 0xffff; - iadev->rfL.pcq_st = readw(iadev->reass_reg+PCQ_ST_ADR) & 0xffff; - iadev->rfL.pcq_ed = readw(iadev->reass_reg+PCQ_ED_ADR) & 0xffff; - iadev->rfL.pcq_rd = readw(iadev->reass_reg+PCQ_RD_PTR) & 0xffff; - iadev->rfL.pcq_wr = readw(iadev->reass_reg+PCQ_WR_PTR) & 0xffff; - - IF_INIT(printk("INIT:pcq_st:0x%x pcq_ed:0x%x pcq_rd:0x%x pcq_wr:0x%x", - iadev->rfL.pcq_st, iadev->rfL.pcq_ed, iadev->rfL.pcq_rd, - iadev->rfL.pcq_wr);) - /* just for check - no VP TBL */ - /* VP Table */ - /* writew(0x0b80, iadev->reass_reg+VP_LKUP_BASE); */ - /* initialize VP Table for invalid VPIs - - I guess we can write all 1s or 0x000f in the entire memory - space or something similar. - */ - - /* This seems to work and looks right to me too !!! */ - i = REASS_TABLE * iadev->memSize; - writew((i >> 3), iadev->reass_reg+REASS_TABLE_BASE); - /* initialize Reassembly table to I don't know what ???? */ - reass_table = (u16 *)(iadev->reass_ram+i); - j = REASS_TABLE_SZ * iadev->memSize; - for(i=0; i < j; i++) - *reass_table++ = NO_AAL5_PKT; - i = 8*1024; - vcsize_sel = 0; - while (i != iadev->num_vc) { - i /= 2; - vcsize_sel++; - } - i = RX_VC_TABLE * iadev->memSize; - writew(((i>>3) & 0xfff8) | vcsize_sel, iadev->reass_reg+VC_LKUP_BASE); - vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); - j = RX_VC_TABLE_SZ * iadev->memSize; - for(i = 0; i < j; i++) - { - /* shift the reassembly pointer by 3 + lower 3 bits of - vc_lkup_base register (=3 for 1K VCs) and the last byte - is those low 3 bits. - Shall program this later. - */ - *vc_table = (i << 6) | 15; /* for invalid VCI */ - vc_table++; - } - /* ABR VC table */ - i = ABR_VC_TABLE * iadev->memSize; - writew(i >> 3, iadev->reass_reg+ABR_LKUP_BASE); - - i = ABR_VC_TABLE * iadev->memSize; - abr_vc_table = (struct abr_vc_table *)(iadev->reass_ram+i); - j = REASS_TABLE_SZ * iadev->memSize; - memset ((char*)abr_vc_table, 0, j * sizeof(*abr_vc_table)); - for(i = 0; i < j; i++) { - abr_vc_table->rdf = 0x0003; - abr_vc_table->air = 0x5eb1; - abr_vc_table++; - } - - /* Initialize other registers */ - - /* VP Filter Register set for VC Reassembly only */ - writew(0xff00, iadev->reass_reg+VP_FILTER); - writew(0, iadev->reass_reg+XTRA_RM_OFFSET); - writew(0x1, iadev->reass_reg+PROTOCOL_ID); - - /* Packet Timeout Count related Registers : - Set packet timeout to occur in about 3 seconds - Set Packet Aging Interval count register to overflow in about 4 us - */ - writew(0xF6F8, iadev->reass_reg+PKT_TM_CNT ); - - i = (j >> 6) & 0xFF; - j += 2 * (j - 1); - i |= ((j << 2) & 0xFF00); - writew(i, iadev->reass_reg+TMOUT_RANGE); - - /* initiate the desc_tble */ - for(i=0; inum_tx_desc;i++) - iadev->desc_tbl[i].timestamp = 0; - - /* to clear the interrupt status register - read it */ - readw(iadev->reass_reg+REASS_INTR_STATUS_REG); - - /* Mask Register - clear it */ - writew(~(RX_FREEQ_EMPT|RX_PKT_RCVD), iadev->reass_reg+REASS_MASK_REG); - - skb_queue_head_init(&iadev->rx_dma_q); - iadev->rx_free_desc_qhead = NULL; - - iadev->rx_open = kcalloc(iadev->num_vc, sizeof(void *), GFP_KERNEL); - if (!iadev->rx_open) { - printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n", - dev->number); - goto err_free_dle; - } - - iadev->rxing = 1; - iadev->rx_pkt_cnt = 0; - /* Mode Register */ - writew(R_ONLINE, iadev->reass_reg+MODE_REG); - return 0; - -err_free_dle: - dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, - iadev->rx_dle_dma); -err_out: - return -ENOMEM; -} - - -/* - The memory map suggested in appendix A and the coding for it. - Keeping it around just in case we change our mind later. - - Buffer descr 0x0000 (128 - 4K) - UBR sched 0x1000 (1K - 4K) - UBR Wait q 0x2000 (1K - 4K) - Commn queues 0x3000 Packet Ready, Trasmit comp(0x3100) - (128 - 256) each - extended VC 0x4000 (1K - 8K) - ABR sched 0x6000 and ABR wait queue (1K - 2K) each - CBR sched 0x7000 (as needed) - VC table 0x8000 (1K - 32K) -*/ - -static void tx_intr(struct atm_dev *dev) -{ - IADEV *iadev; - unsigned short status; - unsigned long flags; - - iadev = INPH_IA_DEV(dev); - - status = readl(iadev->seg_reg+SEG_INTR_STATUS_REG); - if (status & TRANSMIT_DONE){ - - IF_EVENT(printk("Transmit Done Intr logic run\n");) - spin_lock_irqsave(&iadev->tx_lock, flags); - ia_tx_poll(iadev); - spin_unlock_irqrestore(&iadev->tx_lock, flags); - writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); - if (iadev->close_pending) - wake_up(&iadev->close_wait); - } - if (status & TCQ_NOT_EMPTY) - { - IF_EVENT(printk("TCQ_NOT_EMPTY int received\n");) - } -} - -static void tx_dle_intr(struct atm_dev *dev) -{ - IADEV *iadev; - struct dle *dle, *cur_dle; - struct sk_buff *skb; - struct atm_vcc *vcc; - struct ia_vcc *iavcc; - u_int dle_lp; - unsigned long flags; - - iadev = INPH_IA_DEV(dev); - spin_lock_irqsave(&iadev->tx_lock, flags); - dle = iadev->tx_dle_q.read; - dle_lp = readl(iadev->dma+IPHASE5575_TX_LIST_ADDR) & - (sizeof(struct dle)*DLE_ENTRIES - 1); - cur_dle = (struct dle*)(iadev->tx_dle_q.start + (dle_lp >> 4)); - while (dle != cur_dle) - { - /* free the DMAed skb */ - skb = skb_dequeue(&iadev->tx_dma_q); - if (!skb) break; - - /* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */ - if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) { - dma_unmap_single(&iadev->pci->dev, dle->sys_pkt_addr, skb->len, - DMA_TO_DEVICE); - } - vcc = ATM_SKB(skb)->vcc; - if (!vcc) { - printk("tx_dle_intr: vcc is null\n"); - spin_unlock_irqrestore(&iadev->tx_lock, flags); - dev_kfree_skb_any(skb); - - return; - } - iavcc = INPH_IA_VCC(vcc); - if (!iavcc) { - printk("tx_dle_intr: iavcc is null\n"); - spin_unlock_irqrestore(&iadev->tx_lock, flags); - dev_kfree_skb_any(skb); - return; - } - if (vcc->qos.txtp.pcr >= iadev->rate_limit) { - if ((vcc->pop) && (skb->len != 0)) - { - vcc->pop(vcc, skb); - } - else { - dev_kfree_skb_any(skb); - } - } - else { /* Hold the rate-limited skb for flow control */ - IA_SKB_STATE(skb) |= IA_DLED; - skb_queue_tail(&iavcc->txing_skb, skb); - } - IF_EVENT(printk("tx_dle_intr: enque skb = 0x%p \n", skb);) - if (++dle == iadev->tx_dle_q.end) - dle = iadev->tx_dle_q.start; - } - iadev->tx_dle_q.read = dle; - spin_unlock_irqrestore(&iadev->tx_lock, flags); -} - -static int open_tx(struct atm_vcc *vcc) -{ - struct ia_vcc *ia_vcc; - IADEV *iadev; - struct main_vc *vc; - struct ext_vc *evc; - int ret; - IF_EVENT(printk("iadev: open_tx entered vcc->vci = %d\n", vcc->vci);) - if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0; - iadev = INPH_IA_DEV(vcc->dev); - - if (iadev->phy_type & FE_25MBIT_PHY) { - if (vcc->qos.txtp.traffic_class == ATM_ABR) { - printk("IA: ABR not support\n"); - return -EINVAL; - } - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - printk("IA: CBR not support\n"); - return -EINVAL; - } - } - ia_vcc = INPH_IA_VCC(vcc); - memset((caddr_t)ia_vcc, 0, sizeof(*ia_vcc)); - if (vcc->qos.txtp.max_sdu > - (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){ - printk("IA: SDU size over (%d) the configured SDU size %d\n", - vcc->qos.txtp.max_sdu,iadev->tx_buf_sz); - vcc->dev_data = NULL; - kfree(ia_vcc); - return -EINVAL; - } - ia_vcc->vc_desc_cnt = 0; - ia_vcc->txing = 1; - - /* find pcr */ - if (vcc->qos.txtp.max_pcr == ATM_MAX_PCR) - vcc->qos.txtp.pcr = iadev->LineRate; - else if ((vcc->qos.txtp.max_pcr == 0)&&( vcc->qos.txtp.pcr <= 0)) - vcc->qos.txtp.pcr = iadev->LineRate; - else if ((vcc->qos.txtp.max_pcr > vcc->qos.txtp.pcr) && (vcc->qos.txtp.max_pcr> 0)) - vcc->qos.txtp.pcr = vcc->qos.txtp.max_pcr; - if (vcc->qos.txtp.pcr > iadev->LineRate) - vcc->qos.txtp.pcr = iadev->LineRate; - ia_vcc->pcr = vcc->qos.txtp.pcr; - - if (ia_vcc->pcr > (iadev->LineRate / 6) ) ia_vcc->ltimeout = HZ / 10; - else if (ia_vcc->pcr > (iadev->LineRate / 130)) ia_vcc->ltimeout = HZ; - else if (ia_vcc->pcr <= 170) ia_vcc->ltimeout = 16 * HZ; - else ia_vcc->ltimeout = 2700 * HZ / ia_vcc->pcr; - if (ia_vcc->pcr < iadev->rate_limit) - skb_queue_head_init (&ia_vcc->txing_skb); - if (ia_vcc->pcr < iadev->rate_limit) { - struct sock *sk = sk_atm(vcc); - - if (vcc->qos.txtp.max_sdu != 0) { - if (ia_vcc->pcr > 60000) - sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 5; - else if (ia_vcc->pcr > 2000) - sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 4; - else - sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 3; - } - else - sk->sk_sndbuf = 24576; - } - - vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; - evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; - vc += vcc->vci; - evc += vcc->vci; - memset((caddr_t)vc, 0, sizeof(*vc)); - memset((caddr_t)evc, 0, sizeof(*evc)); - - /* store the most significant 4 bits of vci as the last 4 bits - of first part of atm header. - store the last 12 bits of vci as first 12 bits of the second - part of the atm header. - */ - evc->atm_hdr1 = (vcc->vci >> 12) & 0x000f; - evc->atm_hdr2 = (vcc->vci & 0x0fff) << 4; - - /* check the following for different traffic classes */ - if (vcc->qos.txtp.traffic_class == ATM_UBR) - { - vc->type = UBR; - vc->status = CRC_APPEND; - vc->acr = cellrate_to_float(iadev->LineRate); - if (vcc->qos.txtp.pcr > 0) - vc->acr = cellrate_to_float(vcc->qos.txtp.pcr); - IF_UBR(printk("UBR: txtp.pcr = 0x%x f_rate = 0x%x\n", - vcc->qos.txtp.max_pcr,vc->acr);) - } - else if (vcc->qos.txtp.traffic_class == ATM_ABR) - { srv_cls_param_t srv_p; - IF_ABR(printk("Tx ABR VCC\n");) - init_abr_vc(iadev, &srv_p); - if (vcc->qos.txtp.pcr > 0) - srv_p.pcr = vcc->qos.txtp.pcr; - if (vcc->qos.txtp.min_pcr > 0) { - int tmpsum = iadev->sum_mcr+iadev->sum_cbr+vcc->qos.txtp.min_pcr; - if (tmpsum > iadev->LineRate) - return -EBUSY; - srv_p.mcr = vcc->qos.txtp.min_pcr; - iadev->sum_mcr += vcc->qos.txtp.min_pcr; - } - else srv_p.mcr = 0; - if (vcc->qos.txtp.icr) - srv_p.icr = vcc->qos.txtp.icr; - if (vcc->qos.txtp.tbe) - srv_p.tbe = vcc->qos.txtp.tbe; - if (vcc->qos.txtp.frtt) - srv_p.frtt = vcc->qos.txtp.frtt; - if (vcc->qos.txtp.rif) - srv_p.rif = vcc->qos.txtp.rif; - if (vcc->qos.txtp.rdf) - srv_p.rdf = vcc->qos.txtp.rdf; - if (vcc->qos.txtp.nrm_pres) - srv_p.nrm = vcc->qos.txtp.nrm; - if (vcc->qos.txtp.trm_pres) - srv_p.trm = vcc->qos.txtp.trm; - if (vcc->qos.txtp.adtf_pres) - srv_p.adtf = vcc->qos.txtp.adtf; - if (vcc->qos.txtp.cdf_pres) - srv_p.cdf = vcc->qos.txtp.cdf; - if (srv_p.icr > srv_p.pcr) - srv_p.icr = srv_p.pcr; - IF_ABR(printk("ABR:vcc->qos.txtp.max_pcr = %d mcr = %d\n", - srv_p.pcr, srv_p.mcr);) - ia_open_abr_vc(iadev, &srv_p, vcc, 1); - } else if (vcc->qos.txtp.traffic_class == ATM_CBR) { - if (iadev->phy_type & FE_25MBIT_PHY) { - printk("IA: CBR not support\n"); - return -EINVAL; - } - if (vcc->qos.txtp.max_pcr > iadev->LineRate) { - IF_CBR(printk("PCR is not available\n");) - return -1; - } - vc->type = CBR; - vc->status = CRC_APPEND; - if ((ret = ia_cbr_setup (iadev, vcc)) < 0) { - return ret; - } - } else { - printk("iadev: Non UBR, ABR and CBR traffic not supported\n"); - } - - iadev->testTable[vcc->vci]->vc_status |= VC_ACTIVE; - IF_EVENT(printk("ia open_tx returning \n");) - return 0; -} - - -static int tx_init(struct atm_dev *dev) -{ - IADEV *iadev; - struct tx_buf_desc *buf_desc_ptr; - unsigned int tx_pkt_start; - void *dle_addr; - int i; - u_short tcq_st_adr; - u_short *tcq_start; - u_short prq_st_adr; - u_short *prq_start; - struct main_vc *vc; - struct ext_vc *evc; - u_short tmp16; - u32 vcsize_sel; - - iadev = INPH_IA_DEV(dev); - spin_lock_init(&iadev->tx_lock); - - IF_INIT(printk("Tx MASK REG: 0x%0x\n", - readw(iadev->seg_reg+SEG_MASK_REG));) - - /* Allocate 4k (boundary aligned) bytes */ - dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, - &iadev->tx_dle_dma, GFP_KERNEL); - if (!dle_addr) { - printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n"); - goto err_out; - } - iadev->tx_dle_q.start = (struct dle*)dle_addr; - iadev->tx_dle_q.read = iadev->tx_dle_q.start; - iadev->tx_dle_q.write = iadev->tx_dle_q.start; - iadev->tx_dle_q.end = (struct dle*)((unsigned long)dle_addr+sizeof(struct dle)*DLE_ENTRIES); - - /* write the upper 20 bits of the start address to tx list address register */ - writel(iadev->tx_dle_dma & 0xfffff000, - iadev->dma + IPHASE5575_TX_LIST_ADDR); - writew(0xffff, iadev->seg_reg+SEG_MASK_REG); - writew(0, iadev->seg_reg+MODE_REG_0); - writew(RESET_SEG, iadev->seg_reg+SEG_COMMAND_REG); - iadev->MAIN_VC_TABLE_ADDR = iadev->seg_ram+MAIN_VC_TABLE*iadev->memSize; - iadev->EXT_VC_TABLE_ADDR = iadev->seg_ram+EXT_VC_TABLE*iadev->memSize; - iadev->ABR_SCHED_TABLE_ADDR=iadev->seg_ram+ABR_SCHED_TABLE*iadev->memSize; - - /* - Transmit side control memory map - -------------------------------- - Buffer descr 0x0000 (128 - 4K) - Commn queues 0x1000 Transmit comp, Packet ready(0x1400) - (512 - 1K) each - TCQ - 4K, PRQ - 5K - CBR Table 0x1800 (as needed) - 6K - UBR Table 0x3000 (1K - 4K) - 12K - UBR Wait queue 0x4000 (1K - 4K) - 16K - ABR sched 0x5000 and ABR wait queue (1K - 2K) each - ABR Tbl - 20K, ABR Wq - 22K - extended VC 0x6000 (1K - 8K) - 24K - VC Table 0x8000 (1K - 32K) - 32K - - Between 0x2000 (8K) and 0x3000 (12K) there is 4K space left for VBR Tbl - and Wait q, which can be allotted later. - */ - - /* Buffer Descriptor Table Base address */ - writew(TX_DESC_BASE, iadev->seg_reg+SEG_DESC_BASE); - - /* initialize each entry in the buffer descriptor table */ - buf_desc_ptr =(struct tx_buf_desc *)(iadev->seg_ram+TX_DESC_BASE); - memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr)); - buf_desc_ptr++; - tx_pkt_start = TX_PACKET_RAM; - for(i=1; i<=iadev->num_tx_desc; i++) - { - memset((caddr_t)buf_desc_ptr, 0, sizeof(*buf_desc_ptr)); - buf_desc_ptr->desc_mode = AAL5; - buf_desc_ptr->buf_start_hi = tx_pkt_start >> 16; - buf_desc_ptr->buf_start_lo = tx_pkt_start & 0x0000ffff; - buf_desc_ptr++; - tx_pkt_start += iadev->tx_buf_sz; - } - iadev->tx_buf = kmalloc_objs(*iadev->tx_buf, iadev->num_tx_desc); - if (!iadev->tx_buf) { - printk(KERN_ERR DEV_LABEL " couldn't get mem\n"); - goto err_free_dle; - } - for (i= 0; i< iadev->num_tx_desc; i++) - { - struct cpcs_trailer *cpcs; - - cpcs = kmalloc_obj(*cpcs, GFP_KERNEL | GFP_DMA); - if(!cpcs) { - printk(KERN_ERR DEV_LABEL " couldn't get freepage\n"); - goto err_free_tx_bufs; - } - iadev->tx_buf[i].cpcs = cpcs; - iadev->tx_buf[i].dma_addr = dma_map_single(&iadev->pci->dev, - cpcs, - sizeof(*cpcs), - DMA_TO_DEVICE); - } - iadev->desc_tbl = kmalloc_objs(*iadev->desc_tbl, iadev->num_tx_desc); - if (!iadev->desc_tbl) { - printk(KERN_ERR DEV_LABEL " couldn't get mem\n"); - goto err_free_all_tx_bufs; - } - - /* Communication Queues base address */ - i = TX_COMP_Q * iadev->memSize; - writew(i >> 16, iadev->seg_reg+SEG_QUEUE_BASE); - - /* Transmit Complete Queue */ - writew(i, iadev->seg_reg+TCQ_ST_ADR); - writew(i, iadev->seg_reg+TCQ_RD_PTR); - writew(i+iadev->num_tx_desc*sizeof(u_short),iadev->seg_reg+TCQ_WR_PTR); - iadev->host_tcq_wr = i + iadev->num_tx_desc*sizeof(u_short); - writew(i+2 * iadev->num_tx_desc * sizeof(u_short), - iadev->seg_reg+TCQ_ED_ADR); - /* Fill the TCQ with all the free descriptors. */ - tcq_st_adr = readw(iadev->seg_reg+TCQ_ST_ADR); - tcq_start = (u_short *)(iadev->seg_ram+tcq_st_adr); - for(i=1; i<=iadev->num_tx_desc; i++) - { - *tcq_start = (u_short)i; - tcq_start++; - } - - /* Packet Ready Queue */ - i = PKT_RDY_Q * iadev->memSize; - writew(i, iadev->seg_reg+PRQ_ST_ADR); - writew(i+2 * iadev->num_tx_desc * sizeof(u_short), - iadev->seg_reg+PRQ_ED_ADR); - writew(i, iadev->seg_reg+PRQ_RD_PTR); - writew(i, iadev->seg_reg+PRQ_WR_PTR); - - /* Load local copy of PRQ and TCQ ptrs */ - iadev->ffL.prq_st = readw(iadev->seg_reg+PRQ_ST_ADR) & 0xffff; - iadev->ffL.prq_ed = readw(iadev->seg_reg+PRQ_ED_ADR) & 0xffff; - iadev->ffL.prq_wr = readw(iadev->seg_reg+PRQ_WR_PTR) & 0xffff; - - iadev->ffL.tcq_st = readw(iadev->seg_reg+TCQ_ST_ADR) & 0xffff; - iadev->ffL.tcq_ed = readw(iadev->seg_reg+TCQ_ED_ADR) & 0xffff; - iadev->ffL.tcq_rd = readw(iadev->seg_reg+TCQ_RD_PTR) & 0xffff; - - /* Just for safety initializing the queue to have desc 1 always */ - /* Fill the PRQ with all the free descriptors. */ - prq_st_adr = readw(iadev->seg_reg+PRQ_ST_ADR); - prq_start = (u_short *)(iadev->seg_ram+prq_st_adr); - for(i=1; i<=iadev->num_tx_desc; i++) - { - *prq_start = (u_short)0; /* desc 1 in all entries */ - prq_start++; - } - /* CBR Table */ - IF_INIT(printk("Start CBR Init\n");) -#if 1 /* for 1K VC board, CBR_PTR_BASE is 0 */ - writew(0,iadev->seg_reg+CBR_PTR_BASE); -#else /* Charlie's logic is wrong ? */ - tmp16 = (iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize)>>17; - IF_INIT(printk("cbr_ptr_base = 0x%x ", tmp16);) - writew(tmp16,iadev->seg_reg+CBR_PTR_BASE); -#endif - - IF_INIT(printk("value in register = 0x%x\n", - readw(iadev->seg_reg+CBR_PTR_BASE));) - tmp16 = (CBR_SCHED_TABLE*iadev->memSize) >> 1; - writew(tmp16, iadev->seg_reg+CBR_TAB_BEG); - IF_INIT(printk("cbr_tab_beg = 0x%x in reg = 0x%x \n", tmp16, - readw(iadev->seg_reg+CBR_TAB_BEG));) - writew(tmp16, iadev->seg_reg+CBR_TAB_END+1); // CBR_PTR; - tmp16 = (CBR_SCHED_TABLE*iadev->memSize + iadev->num_vc*6 - 2) >> 1; - writew(tmp16, iadev->seg_reg+CBR_TAB_END); - IF_INIT(printk("iadev->seg_reg = 0x%p CBR_PTR_BASE = 0x%x\n", - iadev->seg_reg, readw(iadev->seg_reg+CBR_PTR_BASE));) - IF_INIT(printk("CBR_TAB_BEG = 0x%x, CBR_TAB_END = 0x%x, CBR_PTR = 0x%x\n", - readw(iadev->seg_reg+CBR_TAB_BEG), readw(iadev->seg_reg+CBR_TAB_END), - readw(iadev->seg_reg+CBR_TAB_END+1));) - - /* Initialize the CBR Schedualing Table */ - memset_io(iadev->seg_ram+CBR_SCHED_TABLE*iadev->memSize, - 0, iadev->num_vc*6); - iadev->CbrRemEntries = iadev->CbrTotEntries = iadev->num_vc*3; - iadev->CbrEntryPt = 0; - iadev->Granularity = MAX_ATM_155 / iadev->CbrTotEntries; - iadev->NumEnabledCBR = 0; - - /* UBR scheduling Table and wait queue */ - /* initialize all bytes of UBR scheduler table and wait queue to 0 - - SCHEDSZ is 1K (# of entries). - - UBR Table size is 4K - - UBR wait queue is 4K - since the table and wait queues are contiguous, all the bytes - can be initialized by one memeset. - */ - - vcsize_sel = 0; - i = 8*1024; - while (i != iadev->num_vc) { - i /= 2; - vcsize_sel++; - } - - i = MAIN_VC_TABLE * iadev->memSize; - writew(vcsize_sel | ((i >> 8) & 0xfff8),iadev->seg_reg+VCT_BASE); - i = EXT_VC_TABLE * iadev->memSize; - writew((i >> 8) & 0xfffe, iadev->seg_reg+VCTE_BASE); - i = UBR_SCHED_TABLE * iadev->memSize; - writew((i & 0xffff) >> 11, iadev->seg_reg+UBR_SBPTR_BASE); - i = UBR_WAIT_Q * iadev->memSize; - writew((i >> 7) & 0xffff, iadev->seg_reg+UBRWQ_BASE); - memset((caddr_t)(iadev->seg_ram+UBR_SCHED_TABLE*iadev->memSize), - 0, iadev->num_vc*8); - /* ABR scheduling Table(0x5000-0x57ff) and wait queue(0x5800-0x5fff)*/ - /* initialize all bytes of ABR scheduler table and wait queue to 0 - - SCHEDSZ is 1K (# of entries). - - ABR Table size is 2K - - ABR wait queue is 2K - since the table and wait queues are contiguous, all the bytes - can be initialized by one memeset. - */ - i = ABR_SCHED_TABLE * iadev->memSize; - writew((i >> 11) & 0xffff, iadev->seg_reg+ABR_SBPTR_BASE); - i = ABR_WAIT_Q * iadev->memSize; - writew((i >> 7) & 0xffff, iadev->seg_reg+ABRWQ_BASE); - - i = ABR_SCHED_TABLE*iadev->memSize; - memset((caddr_t)(iadev->seg_ram+i), 0, iadev->num_vc*4); - vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; - evc = (struct ext_vc *)iadev->EXT_VC_TABLE_ADDR; - iadev->testTable = kmalloc_objs(*iadev->testTable, iadev->num_vc); - if (!iadev->testTable) { - printk("Get freepage failed\n"); - goto err_free_desc_tbl; - } - for(i=0; inum_vc; i++) - { - memset((caddr_t)vc, 0, sizeof(*vc)); - memset((caddr_t)evc, 0, sizeof(*evc)); - iadev->testTable[i] = kmalloc_obj(struct testTable_t); - if (!iadev->testTable[i]) - goto err_free_test_tables; - iadev->testTable[i]->lastTime = 0; - iadev->testTable[i]->fract = 0; - iadev->testTable[i]->vc_status = VC_UBR; - vc++; - evc++; - } - - /* Other Initialization */ - - /* Max Rate Register */ - if (iadev->phy_type & FE_25MBIT_PHY) { - writew(RATE25, iadev->seg_reg+MAXRATE); - writew((UBR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); - } - else { - writew(cellrate_to_float(iadev->LineRate),iadev->seg_reg+MAXRATE); - writew((UBR_EN | ABR_EN | (0x23 << 2)), iadev->seg_reg+STPARMS); - } - /* Set Idle Header Reigisters to be sure */ - writew(0, iadev->seg_reg+IDLEHEADHI); - writew(0, iadev->seg_reg+IDLEHEADLO); - - /* Program ABR UBR Priority Register as PRI_ABR_UBR_EQUAL */ - writew(0xaa00, iadev->seg_reg+ABRUBR_ARB); - - iadev->close_pending = 0; - init_waitqueue_head(&iadev->close_wait); - init_waitqueue_head(&iadev->timeout_wait); - skb_queue_head_init(&iadev->tx_dma_q); - ia_init_rtn_q(&iadev->tx_return_q); - - /* RM Cell Protocol ID and Message Type */ - writew(RM_TYPE_4_0, iadev->seg_reg+RM_TYPE); - skb_queue_head_init (&iadev->tx_backlog); - - /* Mode Register 1 */ - writew(MODE_REG_1_VAL, iadev->seg_reg+MODE_REG_1); - - /* Mode Register 0 */ - writew(T_ONLINE, iadev->seg_reg+MODE_REG_0); - - /* Interrupt Status Register - read to clear */ - readw(iadev->seg_reg+SEG_INTR_STATUS_REG); - - /* Interrupt Mask Reg- don't mask TCQ_NOT_EMPTY interrupt generation */ - writew(~(TRANSMIT_DONE | TCQ_NOT_EMPTY), iadev->seg_reg+SEG_MASK_REG); - writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); - iadev->tx_pkt_cnt = 0; - iadev->rate_limit = iadev->LineRate / 3; - - return 0; - -err_free_test_tables: - while (--i >= 0) - kfree(iadev->testTable[i]); - kfree(iadev->testTable); -err_free_desc_tbl: - kfree(iadev->desc_tbl); -err_free_all_tx_bufs: - i = iadev->num_tx_desc; -err_free_tx_bufs: - while (--i >= 0) { - struct cpcs_trailer_desc *desc = iadev->tx_buf + i; - - dma_unmap_single(&iadev->pci->dev, desc->dma_addr, - sizeof(*desc->cpcs), DMA_TO_DEVICE); - kfree(desc->cpcs); - } - kfree(iadev->tx_buf); -err_free_dle: - dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, - iadev->tx_dle_dma); -err_out: - return -ENOMEM; -} - -static irqreturn_t ia_int(int irq, void *dev_id) -{ - struct atm_dev *dev; - IADEV *iadev; - unsigned int status; - int handled = 0; - - dev = dev_id; - iadev = INPH_IA_DEV(dev); - while( (status = readl(iadev->reg+IPHASE5575_BUS_STATUS_REG) & 0x7f)) - { - handled = 1; - IF_EVENT(printk("ia_int: status = 0x%x\n", status);) - if (status & STAT_REASSINT) - { - /* do something */ - IF_EVENT(printk("REASSINT Bus status reg: %08x\n", status);) - rx_intr(dev); - } - if (status & STAT_DLERINT) - { - /* Clear this bit by writing a 1 to it. */ - writel(STAT_DLERINT, iadev->reg + IPHASE5575_BUS_STATUS_REG); - rx_dle_intr(dev); - } - if (status & STAT_SEGINT) - { - /* do something */ - IF_EVENT(printk("IA: tx_intr \n");) - tx_intr(dev); - } - if (status & STAT_DLETINT) - { - writel(STAT_DLETINT, iadev->reg + IPHASE5575_BUS_STATUS_REG); - tx_dle_intr(dev); - } - if (status & (STAT_FEINT | STAT_ERRINT | STAT_MARKINT)) - { - if (status & STAT_FEINT) - ia_frontend_intr(iadev); - } - } - return IRQ_RETVAL(handled); -} - - - -/*----------------------------- entries --------------------------------*/ -static int get_esi(struct atm_dev *dev) -{ - IADEV *iadev; - int i; - u32 mac1; - u16 mac2; - - iadev = INPH_IA_DEV(dev); - mac1 = cpu_to_be32(le32_to_cpu(readl( - iadev->reg+IPHASE5575_MAC1))); - mac2 = cpu_to_be16(le16_to_cpu(readl(iadev->reg+IPHASE5575_MAC2))); - IF_INIT(printk("ESI: 0x%08x%04x\n", mac1, mac2);) - for (i=0; iesi[i] = mac1 >>(8*(MAC1_LEN-1-i)); - - for (i=0; iesi[i+MAC1_LEN] = mac2 >>(8*(MAC2_LEN - 1 -i)); - return 0; -} - -static int reset_sar(struct atm_dev *dev) -{ - IADEV *iadev; - int i, error; - unsigned int pci[64]; - - iadev = INPH_IA_DEV(dev); - for (i = 0; i < 64; i++) { - error = pci_read_config_dword(iadev->pci, i * 4, &pci[i]); - if (error != PCIBIOS_SUCCESSFUL) - return error; - } - writel(0, iadev->reg+IPHASE5575_EXT_RESET); - for (i = 0; i < 64; i++) { - error = pci_write_config_dword(iadev->pci, i * 4, pci[i]); - if (error != PCIBIOS_SUCCESSFUL) - return error; - } - udelay(5); - return 0; -} - - -static int ia_init(struct atm_dev *dev) -{ - IADEV *iadev; - unsigned long real_base; - void __iomem *base; - unsigned short command; - int error, i; - - /* The device has been identified and registered. Now we read - necessary configuration info like memory base address, - interrupt number etc */ - - IF_INIT(printk(">ia_init\n");) - dev->ci_range.vpi_bits = 0; - dev->ci_range.vci_bits = NR_VCI_LD; - - iadev = INPH_IA_DEV(dev); - real_base = pci_resource_start (iadev->pci, 0); - iadev->irq = iadev->pci->irq; - - error = pci_read_config_word(iadev->pci, PCI_COMMAND, &command); - if (error) { - printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%x\n", - dev->number,error); - return -EINVAL; - } - IF_INIT(printk(DEV_LABEL "(itf %d): rev.%d,realbase=0x%lx,irq=%d\n", - dev->number, iadev->pci->revision, real_base, iadev->irq);) - - /* find mapping size of board */ - - iadev->pci_map_size = pci_resource_len(iadev->pci, 0); - - if (iadev->pci_map_size == 0x100000){ - iadev->num_vc = 4096; - dev->ci_range.vci_bits = NR_VCI_4K_LD; - iadev->memSize = 4; - } - else if (iadev->pci_map_size == 0x40000) { - iadev->num_vc = 1024; - iadev->memSize = 1; - } - else { - printk("Unknown pci_map_size = 0x%x\n", iadev->pci_map_size); - return -EINVAL; - } - IF_INIT(printk (DEV_LABEL "map size: %i\n", iadev->pci_map_size);) - - /* enable bus mastering */ - pci_set_master(iadev->pci); - - /* - * Delay at least 1us before doing any mem accesses (how 'bout 10?) - */ - udelay(10); - - /* mapping the physical address to a virtual address in address space */ - base = ioremap(real_base,iadev->pci_map_size); /* ioremap is not resolved ??? */ - - if (!base) - { - printk(DEV_LABEL " (itf %d): can't set up page mapping\n", - dev->number); - return -ENOMEM; - } - IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=%p,irq=%d\n", - dev->number, iadev->pci->revision, base, iadev->irq);) - - /* filling the iphase dev structure */ - iadev->mem = iadev->pci_map_size /2; - iadev->real_base = real_base; - iadev->base = base; - - /* Bus Interface Control Registers */ - iadev->reg = base + REG_BASE; - /* Segmentation Control Registers */ - iadev->seg_reg = base + SEG_BASE; - /* Reassembly Control Registers */ - iadev->reass_reg = base + REASS_BASE; - /* Front end/ DMA control registers */ - iadev->phy = base + PHY_BASE; - iadev->dma = base + PHY_BASE; - /* RAM - Segmentation RAm and Reassembly RAM */ - iadev->ram = base + ACTUAL_RAM_BASE; - iadev->seg_ram = base + ACTUAL_SEG_RAM_BASE; - iadev->reass_ram = base + ACTUAL_REASS_RAM_BASE; - - /* lets print out the above */ - IF_INIT(printk("Base addrs: %p %p %p \n %p %p %p %p\n", - iadev->reg,iadev->seg_reg,iadev->reass_reg, - iadev->phy, iadev->ram, iadev->seg_ram, - iadev->reass_ram);) - - /* lets try reading the MAC address */ - error = get_esi(dev); - if (error) { - iounmap(iadev->base); - return error; - } - printk("IA: "); - for (i=0; i < ESI_LEN; i++) - printk("%s%02X",i ? "-" : "",dev->esi[i]); - printk("\n"); - - /* reset SAR */ - if (reset_sar(dev)) { - iounmap(iadev->base); - printk("IA: reset SAR fail, please try again\n"); - return 1; - } - return 0; -} - -static void ia_update_stats(IADEV *iadev) { - if (!iadev->carrier_detect) - return; - iadev->rx_cell_cnt += readw(iadev->reass_reg+CELL_CTR0)&0xffff; - iadev->rx_cell_cnt += (readw(iadev->reass_reg+CELL_CTR1) & 0xffff) << 16; - iadev->drop_rxpkt += readw(iadev->reass_reg + DRP_PKT_CNTR ) & 0xffff; - iadev->drop_rxcell += readw(iadev->reass_reg + ERR_CNTR) & 0xffff; - iadev->tx_cell_cnt += readw(iadev->seg_reg + CELL_CTR_LO_AUTO)&0xffff; - iadev->tx_cell_cnt += (readw(iadev->seg_reg+CELL_CTR_HIGH_AUTO)&0xffff)<<16; - return; -} - -static void ia_led_timer(struct timer_list *unused) { - unsigned long flags; - static u_char blinking[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - u_char i; - static u32 ctrl_reg; - for (i = 0; i < iadev_count; i++) { - if (ia_dev[i]) { - ctrl_reg = readl(ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); - if (blinking[i] == 0) { - blinking[i]++; - ctrl_reg &= (~CTRL_LED); - writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); - ia_update_stats(ia_dev[i]); - } - else { - blinking[i] = 0; - ctrl_reg |= CTRL_LED; - writel(ctrl_reg, ia_dev[i]->reg+IPHASE5575_BUS_CONTROL_REG); - spin_lock_irqsave(&ia_dev[i]->tx_lock, flags); - if (ia_dev[i]->close_pending) - wake_up(&ia_dev[i]->close_wait); - ia_tx_poll(ia_dev[i]); - spin_unlock_irqrestore(&ia_dev[i]->tx_lock, flags); - } - } - } - mod_timer(&ia_timer, jiffies + HZ / 4); - return; -} - -static void ia_phy_put(struct atm_dev *dev, unsigned char value, - unsigned long addr) -{ - writel(value, INPH_IA_DEV(dev)->phy+addr); -} - -static unsigned char ia_phy_get(struct atm_dev *dev, unsigned long addr) -{ - return readl(INPH_IA_DEV(dev)->phy+addr); -} - -static void ia_free_tx(IADEV *iadev) -{ - int i; - - kfree(iadev->desc_tbl); - for (i = 0; i < iadev->num_vc; i++) - kfree(iadev->testTable[i]); - kfree(iadev->testTable); - for (i = 0; i < iadev->num_tx_desc; i++) { - struct cpcs_trailer_desc *desc = iadev->tx_buf + i; - - dma_unmap_single(&iadev->pci->dev, desc->dma_addr, - sizeof(*desc->cpcs), DMA_TO_DEVICE); - kfree(desc->cpcs); - } - kfree(iadev->tx_buf); - dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start, - iadev->tx_dle_dma); -} - -static void ia_free_rx(IADEV *iadev) -{ - kfree(iadev->rx_open); - dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start, - iadev->rx_dle_dma); -} - -static int ia_start(struct atm_dev *dev) -{ - IADEV *iadev; - int error; - unsigned char phy; - u32 ctrl_reg; - IF_EVENT(printk(">ia_start\n");) - iadev = INPH_IA_DEV(dev); - if (request_irq(iadev->irq, &ia_int, IRQF_SHARED, DEV_LABEL, dev)) { - printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n", - dev->number, iadev->irq); - error = -EAGAIN; - goto err_out; - } - /* @@@ should release IRQ on error */ - /* enabling memory + master */ - if ((error = pci_write_config_word(iadev->pci, - PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ))) - { - printk(KERN_ERR DEV_LABEL "(itf %d): can't enable memory+" - "master (0x%x)\n",dev->number, error); - error = -EIO; - goto err_free_irq; - } - udelay(10); - - /* Maybe we should reset the front end, initialize Bus Interface Control - Registers and see. */ - - IF_INIT(printk("Bus ctrl reg: %08x\n", - readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) - ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); - ctrl_reg = (ctrl_reg & (CTRL_LED | CTRL_FE_RST)) - | CTRL_B8 - | CTRL_B16 - | CTRL_B32 - | CTRL_B48 - | CTRL_B64 - | CTRL_B128 - | CTRL_ERRMASK - | CTRL_DLETMASK /* shud be removed l8r */ - | CTRL_DLERMASK - | CTRL_SEGMASK - | CTRL_REASSMASK - | CTRL_FEMASK - | CTRL_CSPREEMPT; - - writel(ctrl_reg, iadev->reg+IPHASE5575_BUS_CONTROL_REG); - - IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", - readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG)); - printk("Bus status reg after init: %08x\n", - readl(iadev->reg+IPHASE5575_BUS_STATUS_REG));) - - ia_hw_type(iadev); - error = tx_init(dev); - if (error) - goto err_free_irq; - error = rx_init(dev); - if (error) - goto err_free_tx; - - ctrl_reg = readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG); - writel(ctrl_reg | CTRL_FE_RST, iadev->reg+IPHASE5575_BUS_CONTROL_REG); - IF_INIT(printk("Bus ctrl reg after initializing: %08x\n", - readl(iadev->reg+IPHASE5575_BUS_CONTROL_REG));) - phy = 0; /* resolve compiler complaint */ - IF_INIT ( - if ((phy=ia_phy_get(dev,0)) == 0x30) - printk("IA: pm5346,rev.%d\n",phy&0x0f); - else - printk("IA: utopia,rev.%0x\n",phy);) - - if (iadev->phy_type & FE_25MBIT_PHY) - ia_mb25_init(iadev); - else if (iadev->phy_type & (FE_DS3_PHY | FE_E3_PHY)) - ia_suni_pm7345_init(iadev); - else { - error = suni_init(dev); - if (error) - goto err_free_rx; - if (dev->phy->start) { - error = dev->phy->start(dev); - if (error) - goto err_free_rx; - } - /* Get iadev->carrier_detect status */ - ia_frontend_intr(iadev); - } - return 0; - -err_free_rx: - ia_free_rx(iadev); -err_free_tx: - ia_free_tx(iadev); -err_free_irq: - free_irq(iadev->irq, dev); -err_out: - return error; -} - -static void ia_close(struct atm_vcc *vcc) -{ - DEFINE_WAIT(wait); - u16 *vc_table; - IADEV *iadev; - struct ia_vcc *ia_vcc; - struct sk_buff *skb = NULL; - struct sk_buff_head tmp_tx_backlog, tmp_vcc_backlog; - unsigned long closetime, flags; - - iadev = INPH_IA_DEV(vcc->dev); - ia_vcc = INPH_IA_VCC(vcc); - if (!ia_vcc) return; - - IF_EVENT(printk("ia_close: ia_vcc->vc_desc_cnt = %d vci = %d\n", - ia_vcc->vc_desc_cnt,vcc->vci);) - clear_bit(ATM_VF_READY,&vcc->flags); - skb_queue_head_init (&tmp_tx_backlog); - skb_queue_head_init (&tmp_vcc_backlog); - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - iadev->close_pending++; - prepare_to_wait(&iadev->timeout_wait, &wait, TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(500)); - finish_wait(&iadev->timeout_wait, &wait); - spin_lock_irqsave(&iadev->tx_lock, flags); - while((skb = skb_dequeue(&iadev->tx_backlog))) { - if (ATM_SKB(skb)->vcc == vcc){ - if (vcc->pop) vcc->pop(vcc, skb); - else dev_kfree_skb_any(skb); - } - else - skb_queue_tail(&tmp_tx_backlog, skb); - } - while((skb = skb_dequeue(&tmp_tx_backlog))) - skb_queue_tail(&iadev->tx_backlog, skb); - IF_EVENT(printk("IA TX Done decs_cnt = %d\n", ia_vcc->vc_desc_cnt);) - closetime = 300000 / ia_vcc->pcr; - if (closetime == 0) - closetime = 1; - spin_unlock_irqrestore(&iadev->tx_lock, flags); - wait_event_timeout(iadev->close_wait, (ia_vcc->vc_desc_cnt <= 0), closetime); - spin_lock_irqsave(&iadev->tx_lock, flags); - iadev->close_pending--; - iadev->testTable[vcc->vci]->lastTime = 0; - iadev->testTable[vcc->vci]->fract = 0; - iadev->testTable[vcc->vci]->vc_status = VC_UBR; - if (vcc->qos.txtp.traffic_class == ATM_ABR) { - if (vcc->qos.txtp.min_pcr > 0) - iadev->sum_mcr -= vcc->qos.txtp.min_pcr; - } - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - ia_vcc = INPH_IA_VCC(vcc); - iadev->sum_mcr -= ia_vcc->NumCbrEntry*iadev->Granularity; - ia_cbrVc_close (vcc); - } - spin_unlock_irqrestore(&iadev->tx_lock, flags); - } - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - // reset reass table - vc_table = (u16 *)(iadev->reass_ram+REASS_TABLE*iadev->memSize); - vc_table += vcc->vci; - *vc_table = NO_AAL5_PKT; - // reset vc table - vc_table = (u16 *)(iadev->reass_ram+RX_VC_TABLE*iadev->memSize); - vc_table += vcc->vci; - *vc_table = (vcc->vci << 6) | 15; - if (vcc->qos.rxtp.traffic_class == ATM_ABR) { - struct abr_vc_table __iomem *abr_vc_table = - (iadev->reass_ram+ABR_VC_TABLE*iadev->memSize); - abr_vc_table += vcc->vci; - abr_vc_table->rdf = 0x0003; - abr_vc_table->air = 0x5eb1; - } - // Drain the packets - rx_dle_intr(vcc->dev); - iadev->rx_open[vcc->vci] = NULL; - } - kfree(INPH_IA_VCC(vcc)); - ia_vcc = NULL; - vcc->dev_data = NULL; - clear_bit(ATM_VF_ADDR,&vcc->flags); - return; -} - -static int ia_open(struct atm_vcc *vcc) -{ - struct ia_vcc *ia_vcc; - int error; - if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) - { - IF_EVENT(printk("ia: not partially allocated resources\n");) - vcc->dev_data = NULL; - } - if (vcc->vci != ATM_VPI_UNSPEC && vcc->vpi != ATM_VCI_UNSPEC) - { - IF_EVENT(printk("iphase open: unspec part\n");) - set_bit(ATM_VF_ADDR,&vcc->flags); - } - if (vcc->qos.aal != ATM_AAL5) - return -EINVAL; - IF_EVENT(printk(DEV_LABEL "(itf %d): open %d.%d\n", - vcc->dev->number, vcc->vpi, vcc->vci);) - - /* Device dependent initialization */ - ia_vcc = kmalloc_obj(*ia_vcc); - if (!ia_vcc) return -ENOMEM; - vcc->dev_data = ia_vcc; - - if ((error = open_rx(vcc))) - { - IF_EVENT(printk("iadev: error in open_rx, closing\n");) - ia_close(vcc); - return error; - } - - if ((error = open_tx(vcc))) - { - IF_EVENT(printk("iadev: error in open_tx, closing\n");) - ia_close(vcc); - return error; - } - - set_bit(ATM_VF_READY,&vcc->flags); - -#if 0 - { - static u8 first = 1; - if (first) { - ia_timer.expires = jiffies + 3*HZ; - add_timer(&ia_timer); - first = 0; - } - } -#endif - IF_EVENT(printk("ia open returning\n");) - return 0; -} - -static int ia_change_qos(struct atm_vcc *vcc, struct atm_qos *qos, int flags) -{ - IF_EVENT(printk(">ia_change_qos\n");) - return 0; -} - -static int ia_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg) -{ - IA_CMDBUF ia_cmds; - IADEV *iadev; - int i, board; - u16 __user *tmps; - IF_EVENT(printk(">ia_ioctl\n");) - if (cmd != IA_CMD) { - if (!dev->phy->ioctl) return -EINVAL; - return dev->phy->ioctl(dev,cmd,arg); - } - if (copy_from_user(&ia_cmds, arg, sizeof ia_cmds)) return -EFAULT; - board = ia_cmds.status; - - if ((board < 0) || (board > iadev_count)) - board = 0; - board = array_index_nospec(board, iadev_count + 1); - - iadev = ia_dev[board]; - switch (ia_cmds.cmd) { - case MEMDUMP: - { - switch (ia_cmds.sub_cmd) { - case MEMDUMP_SEGREG: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - tmps = (u16 __user *)ia_cmds.buf; - for(i=0; i<0x80; i+=2, tmps++) - if(put_user((u16)(readl(iadev->seg_reg+i) & 0xffff), tmps)) return -EFAULT; - ia_cmds.status = 0; - ia_cmds.len = 0x80; - break; - case MEMDUMP_REASSREG: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - tmps = (u16 __user *)ia_cmds.buf; - for(i=0; i<0x80; i+=2, tmps++) - if(put_user((u16)(readl(iadev->reass_reg+i) & 0xffff), tmps)) return -EFAULT; - ia_cmds.status = 0; - ia_cmds.len = 0x80; - break; - case MEMDUMP_FFL: - { - ia_regs_t *regs_local; - ffredn_t *ffL; - rfredn_t *rfL; - - if (!capable(CAP_NET_ADMIN)) return -EPERM; - regs_local = kmalloc_obj(*regs_local); - if (!regs_local) return -ENOMEM; - ffL = ®s_local->ffredn; - rfL = ®s_local->rfredn; - /* Copy real rfred registers into the local copy */ - for (i=0; i<(sizeof (rfredn_t))/4; i++) - ((u_int *)rfL)[i] = readl(iadev->reass_reg + i) & 0xffff; - /* Copy real ffred registers into the local copy */ - for (i=0; i<(sizeof (ffredn_t))/4; i++) - ((u_int *)ffL)[i] = readl(iadev->seg_reg + i) & 0xffff; - - if (copy_to_user(ia_cmds.buf, regs_local,sizeof(ia_regs_t))) { - kfree(regs_local); - return -EFAULT; - } - kfree(regs_local); - printk("Board %d registers dumped\n", board); - ia_cmds.status = 0; - } - break; - case READ_REG: - { - if (!capable(CAP_NET_ADMIN)) return -EPERM; - desc_dbg(iadev); - ia_cmds.status = 0; - } - break; - case 0x6: - { - ia_cmds.status = 0; - printk("skb = 0x%p\n", skb_peek(&iadev->tx_backlog)); - printk("rtn_q: 0x%p\n",ia_deque_rtn_q(&iadev->tx_return_q)); - } - break; - case 0x8: - { - struct k_sonet_stats *stats; - stats = &PRIV(_ia_dev[board])->sonet_stats; - printk("section_bip: %d\n", atomic_read(&stats->section_bip)); - printk("line_bip : %d\n", atomic_read(&stats->line_bip)); - printk("path_bip : %d\n", atomic_read(&stats->path_bip)); - printk("line_febe : %d\n", atomic_read(&stats->line_febe)); - printk("path_febe : %d\n", atomic_read(&stats->path_febe)); - printk("corr_hcs : %d\n", atomic_read(&stats->corr_hcs)); - printk("uncorr_hcs : %d\n", atomic_read(&stats->uncorr_hcs)); - printk("tx_cells : %d\n", atomic_read(&stats->tx_cells)); - printk("rx_cells : %d\n", atomic_read(&stats->rx_cells)); - } - ia_cmds.status = 0; - break; - case 0x9: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - for (i = 1; i <= iadev->num_rx_desc; i++) - free_desc(_ia_dev[board], i); - writew( ~(RX_FREEQ_EMPT | RX_EXCP_RCVD), - iadev->reass_reg+REASS_MASK_REG); - iadev->rxing = 1; - - ia_cmds.status = 0; - break; - - case 0xb: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - ia_frontend_intr(iadev); - break; - case 0xa: - if (!capable(CAP_NET_ADMIN)) return -EPERM; - { - ia_cmds.status = 0; - IADebugFlag = ia_cmds.maddr; - printk("New debug option loaded\n"); - } - break; - default: - ia_cmds.status = 0; - break; - } - } - break; - default: - break; - - } - return 0; -} - -static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { - IADEV *iadev; - struct dle *wr_ptr; - struct tx_buf_desc __iomem *buf_desc_ptr; - int desc; - int comp_code; - int total_len; - struct cpcs_trailer *trailer; - struct ia_vcc *iavcc; - - iadev = INPH_IA_DEV(vcc->dev); - iavcc = INPH_IA_VCC(vcc); - if (!iavcc->txing) { - printk("discard packet on closed VC\n"); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - return 0; - } - - if (skb->len > iadev->tx_buf_sz - 8) { - printk("Transmit size over tx buffer size\n"); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - return 0; - } - if ((unsigned long)skb->data & 3) { - printk("Misaligned SKB\n"); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - return 0; - } - /* Get a descriptor number from our free descriptor queue - We get the descr number from the TCQ now, since I am using - the TCQ as a free buffer queue. Initially TCQ will be - initialized with all the descriptors and is hence, full. - */ - desc = get_desc (iadev, iavcc); - if (desc == 0xffff) - return 1; - comp_code = desc >> 13; - desc &= 0x1fff; - - if ((desc == 0) || (desc > iadev->num_tx_desc)) - { - IF_ERR(printk(DEV_LABEL "invalid desc for send: %d\n", desc);) - atomic_inc(&vcc->stats->tx); - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); - return 0; /* return SUCCESS */ - } - - if (comp_code) - { - IF_ERR(printk(DEV_LABEL "send desc:%d completion code %d error\n", - desc, comp_code);) - } - - /* remember the desc and vcc mapping */ - iavcc->vc_desc_cnt++; - iadev->desc_tbl[desc-1].iavcc = iavcc; - iadev->desc_tbl[desc-1].txskb = skb; - IA_SKB_STATE(skb) = 0; - - iadev->ffL.tcq_rd += 2; - if (iadev->ffL.tcq_rd > iadev->ffL.tcq_ed) - iadev->ffL.tcq_rd = iadev->ffL.tcq_st; - writew(iadev->ffL.tcq_rd, iadev->seg_reg+TCQ_RD_PTR); - - /* Put the descriptor number in the packet ready queue - and put the updated write pointer in the DLE field - */ - *(u16*)(iadev->seg_ram+iadev->ffL.prq_wr) = desc; - - iadev->ffL.prq_wr += 2; - if (iadev->ffL.prq_wr > iadev->ffL.prq_ed) - iadev->ffL.prq_wr = iadev->ffL.prq_st; - - /* Figure out the exact length of the packet and padding required to - make it aligned on a 48 byte boundary. */ - total_len = skb->len + sizeof(struct cpcs_trailer); - total_len = ((total_len + 47) / 48) * 48; - IF_TX(printk("ia packet len:%d padding:%d\n", total_len, total_len - skb->len);) - - /* Put the packet in a tx buffer */ - trailer = iadev->tx_buf[desc-1].cpcs; - IF_TX(printk("Sent: skb = 0x%p skb->data: 0x%p len: %d, desc: %d\n", - skb, skb->data, skb->len, desc);) - trailer->control = 0; - /*big endian*/ - trailer->length = ((skb->len & 0xff) << 8) | ((skb->len & 0xff00) >> 8); - trailer->crc32 = 0; /* not needed - dummy bytes */ - - /* Display the packet */ - IF_TXPKT(printk("Sent data: len = %d MsgNum = %d\n", - skb->len, tcnter++); - xdump(skb->data, skb->len, "TX: "); - printk("\n");) - - /* Build the buffer descriptor */ - buf_desc_ptr = iadev->seg_ram+TX_DESC_BASE; - buf_desc_ptr += desc; /* points to the corresponding entry */ - buf_desc_ptr->desc_mode = AAL5 | EOM_EN | APP_CRC32 | CMPL_INT; - /* Huh ? p.115 of users guide describes this as a read-only register */ - writew(TRANSMIT_DONE, iadev->seg_reg+SEG_INTR_STATUS_REG); - buf_desc_ptr->vc_index = vcc->vci; - buf_desc_ptr->bytes = total_len; - - if (vcc->qos.txtp.traffic_class == ATM_ABR) - clear_lockup (vcc, iadev); - - /* Build the DLE structure */ - wr_ptr = iadev->tx_dle_q.write; - memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr)); - wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data, - skb->len, DMA_TO_DEVICE); - wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | - buf_desc_ptr->buf_start_lo; - /* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */ - wr_ptr->bytes = skb->len; - - /* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */ - if ((wr_ptr->bytes >> 2) == 0xb) - wr_ptr->bytes = 0x30; - - wr_ptr->mode = TX_DLE_PSI; - wr_ptr->prq_wr_ptr_data = 0; - - /* end is not to be used for the DLE q */ - if (++wr_ptr == iadev->tx_dle_q.end) - wr_ptr = iadev->tx_dle_q.start; - - /* Build trailer dle */ - wr_ptr->sys_pkt_addr = iadev->tx_buf[desc-1].dma_addr; - wr_ptr->local_pkt_addr = ((buf_desc_ptr->buf_start_hi << 16) | - buf_desc_ptr->buf_start_lo) + total_len - sizeof(struct cpcs_trailer); - - wr_ptr->bytes = sizeof(struct cpcs_trailer); - wr_ptr->mode = DMA_INT_ENABLE; - wr_ptr->prq_wr_ptr_data = iadev->ffL.prq_wr; - - /* end is not to be used for the DLE q */ - if (++wr_ptr == iadev->tx_dle_q.end) - wr_ptr = iadev->tx_dle_q.start; - - iadev->tx_dle_q.write = wr_ptr; - ATM_DESC(skb) = vcc->vci; - skb_queue_tail(&iadev->tx_dma_q, skb); - - atomic_inc(&vcc->stats->tx); - iadev->tx_pkt_cnt++; - /* Increment transaction counter */ - writel(2, iadev->dma+IPHASE5575_TX_COUNTER); - -#if 0 - /* add flow control logic */ - if (atomic_read(&vcc->stats->tx) % 20 == 0) { - if (iavcc->vc_desc_cnt > 10) { - vcc->tx_quota = vcc->tx_quota * 3 / 4; - printk("Tx1: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); - iavcc->flow_inc = -1; - iavcc->saved_tx_quota = vcc->tx_quota; - } else if ((iavcc->flow_inc < 0) && (iavcc->vc_desc_cnt < 3)) { - // vcc->tx_quota = 3 * iavcc->saved_tx_quota / 4; - printk("Tx2: vcc->tx_quota = %d \n", (u32)vcc->tx_quota ); - iavcc->flow_inc = 0; - } - } -#endif - IF_TX(printk("ia send done\n");) - return 0; -} - -static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - IADEV *iadev; - unsigned long flags; - - iadev = INPH_IA_DEV(vcc->dev); - if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer)))) - { - if (!skb) - printk(KERN_CRIT "null skb in ia_send\n"); - else dev_kfree_skb_any(skb); - return -EINVAL; - } - spin_lock_irqsave(&iadev->tx_lock, flags); - if (!test_bit(ATM_VF_READY,&vcc->flags)){ - dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&iadev->tx_lock, flags); - return -EINVAL; - } - ATM_SKB(skb)->vcc = vcc; - - if (skb_peek(&iadev->tx_backlog)) { - skb_queue_tail(&iadev->tx_backlog, skb); - } - else { - if (ia_pkt_tx (vcc, skb)) { - skb_queue_tail(&iadev->tx_backlog, skb); - } - } - spin_unlock_irqrestore(&iadev->tx_lock, flags); - return 0; - -} - -static int ia_proc_read(struct atm_dev *dev,loff_t *pos,char *page) -{ - int left = *pos, n; - char *tmpPtr; - IADEV *iadev = INPH_IA_DEV(dev); - if(!left--) { - if (iadev->phy_type == FE_25MBIT_PHY) { - n = sprintf(page, " Board Type : Iphase5525-1KVC-128K\n"); - return n; - } - if (iadev->phy_type == FE_DS3_PHY) - n = sprintf(page, " Board Type : Iphase-ATM-DS3"); - else if (iadev->phy_type == FE_E3_PHY) - n = sprintf(page, " Board Type : Iphase-ATM-E3"); - else if (iadev->phy_type == FE_UTP_OPTION) - n = sprintf(page, " Board Type : Iphase-ATM-UTP155"); - else - n = sprintf(page, " Board Type : Iphase-ATM-OC3"); - tmpPtr = page + n; - if (iadev->pci_map_size == 0x40000) - n += sprintf(tmpPtr, "-1KVC-"); - else - n += sprintf(tmpPtr, "-4KVC-"); - tmpPtr = page + n; - if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_1M) - n += sprintf(tmpPtr, "1M \n"); - else if ((iadev->memType & MEM_SIZE_MASK) == MEM_SIZE_512K) - n += sprintf(tmpPtr, "512K\n"); - else - n += sprintf(tmpPtr, "128K\n"); - return n; - } - if (!left) { - return sprintf(page, " Number of Tx Buffer: %u\n" - " Size of Tx Buffer : %u\n" - " Number of Rx Buffer: %u\n" - " Size of Rx Buffer : %u\n" - " Packets Received : %u\n" - " Packets Transmitted: %u\n" - " Cells Received : %u\n" - " Cells Transmitted : %u\n" - " Board Dropped Cells: %u\n" - " Board Dropped Pkts : %u\n", - iadev->num_tx_desc, iadev->tx_buf_sz, - iadev->num_rx_desc, iadev->rx_buf_sz, - iadev->rx_pkt_cnt, iadev->tx_pkt_cnt, - iadev->rx_cell_cnt, iadev->tx_cell_cnt, - iadev->drop_rxcell, iadev->drop_rxpkt); - } - return 0; -} - -static const struct atmdev_ops ops = { - .open = ia_open, - .close = ia_close, - .ioctl = ia_ioctl, - .send = ia_send, - .phy_put = ia_phy_put, - .phy_get = ia_phy_get, - .change_qos = ia_change_qos, - .proc_read = ia_proc_read, - .owner = THIS_MODULE, -}; - -static int ia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct atm_dev *dev; - IADEV *iadev; - int ret; - - iadev = kzalloc_obj(*iadev); - if (!iadev) { - ret = -ENOMEM; - goto err_out; - } - - iadev->pci = pdev; - - IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n", - pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));) - if (pci_enable_device(pdev)) { - ret = -ENODEV; - goto err_out_free_iadev; - } - dev = atm_dev_register(DEV_LABEL, &pdev->dev, &ops, -1, NULL); - if (!dev) { - ret = -ENOMEM; - goto err_out_disable_dev; - } - dev->dev_data = iadev; - IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);) - IF_INIT(printk("dev_id = 0x%p iadev->LineRate = %d \n", dev, - iadev->LineRate);) - - pci_set_drvdata(pdev, dev); - - ia_dev[iadev_count] = iadev; - _ia_dev[iadev_count] = dev; - iadev_count++; - if (ia_init(dev) || ia_start(dev)) { - IF_INIT(printk("IA register failed!\n");) - iadev_count--; - ia_dev[iadev_count] = NULL; - _ia_dev[iadev_count] = NULL; - ret = -EINVAL; - goto err_out_deregister_dev; - } - IF_EVENT(printk("iadev_count = %d\n", iadev_count);) - - iadev->next_board = ia_boards; - ia_boards = dev; - - return 0; - -err_out_deregister_dev: - atm_dev_deregister(dev); -err_out_disable_dev: - pci_disable_device(pdev); -err_out_free_iadev: - kfree(iadev); -err_out: - return ret; -} - -static void ia_remove_one(struct pci_dev *pdev) -{ - struct atm_dev *dev = pci_get_drvdata(pdev); - IADEV *iadev = INPH_IA_DEV(dev); - - /* Disable phy interrupts */ - ia_phy_put(dev, ia_phy_get(dev, SUNI_RSOP_CIE) & ~(SUNI_RSOP_CIE_LOSE), - SUNI_RSOP_CIE); - udelay(1); - - if (dev->phy && dev->phy->stop) - dev->phy->stop(dev); - - /* De-register device */ - free_irq(iadev->irq, dev); - iadev_count--; - ia_dev[iadev_count] = NULL; - _ia_dev[iadev_count] = NULL; - IF_EVENT(printk("deregistering iav at (itf:%d)\n", dev->number);) - atm_dev_deregister(dev); - - iounmap(iadev->base); - pci_disable_device(pdev); - - ia_free_rx(iadev); - ia_free_tx(iadev); - - kfree(iadev); -} - -static const struct pci_device_id ia_pci_tbl[] = { - { PCI_VENDOR_ID_IPHASE, 0x0008, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_IPHASE, 0x0009, PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} -}; -MODULE_DEVICE_TABLE(pci, ia_pci_tbl); - -static struct pci_driver ia_driver = { - .name = DEV_LABEL, - .id_table = ia_pci_tbl, - .probe = ia_init_one, - .remove = ia_remove_one, -}; - -static int __init ia_module_init(void) -{ - int ret; - - ret = pci_register_driver(&ia_driver); - if (ret >= 0) { - ia_timer.expires = jiffies + 3*HZ; - add_timer(&ia_timer); - } else - printk(KERN_ERR DEV_LABEL ": no adapter found\n"); - return ret; -} - -static void __exit ia_module_exit(void) -{ - pci_unregister_driver(&ia_driver); - - timer_delete_sync(&ia_timer); -} - -module_init(ia_module_init); -module_exit(ia_module_exit); diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c deleted file mode 100644 index d6af999a9ebb..000000000000 --- a/drivers/atm/lanai.c +++ /dev/null @@ -1,2603 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* lanai.c -- Copyright 1999-2003 by Mitchell Blank Jr - * - * This driver supports ATM cards based on the Efficient "Lanai" - * chipset such as the Speedstream 3010 and the ENI-25p. The - * Speedstream 3060 is currently not supported since we don't - * have the code to drive the on-board Alcatel DSL chipset (yet). - * - * Thanks to Efficient for supporting this project with hardware, - * documentation, and by answering my questions. - * - * Things not working yet: - * - * o We don't support the Speedstream 3060 yet - this card has - * an on-board DSL modem chip by Alcatel and the driver will - * need some extra code added to handle it - * - * o Note that due to limitations of the Lanai only one VCC can be - * in CBR at once - * - * o We don't currently parse the EEPROM at all. The code is all - * there as per the spec, but it doesn't actually work. I think - * there may be some issues with the docs. Anyway, do NOT - * enable it yet - bugs in that code may actually damage your - * hardware! Because of this you should hardware an ESI before - * trying to use this in a LANE or MPOA environment. - * - * o AAL0 is stubbed in but the actual rx/tx path isn't written yet: - * vcc_tx_aal0() needs to send or queue a SKB - * vcc_tx_unqueue_aal0() needs to attempt to send queued SKBs - * vcc_rx_aal0() needs to handle AAL0 interrupts - * This isn't too much work - I just wanted to get other things - * done first. - * - * o lanai_change_qos() isn't written yet - * - * o There aren't any ioctl's yet -- I'd like to eventually support - * setting loopback and LED modes that way. - * - * o If the segmentation engine or DMA gets shut down we should restart - * card as per section 17.0i. (see lanai_reset) - * - * o setsockopt(SO_CIRANGE) isn't done (although despite what the - * API says it isn't exactly commonly implemented) - */ - -/* Version history: - * v.1.00 -- 26-JUL-2003 -- PCI/DMA updates - * v.0.02 -- 11-JAN-2000 -- Endian fixes - * v.0.01 -- 30-NOV-1999 -- Initial release - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -------------------- TUNABLE PARAMATERS: */ - -/* - * Maximum number of VCIs per card. Setting it lower could theoretically - * save some memory, but since we allocate our vcc list with get_free_pages, - * it's not really likely for most architectures - */ -#define NUM_VCI (1024) - -/* - * Enable extra debugging - */ -#define DEBUG -/* - * Debug _all_ register operations with card, except the memory test. - * Also disables the timed poll to prevent extra chattiness. This - * isn't for normal use - */ -#undef DEBUG_RW - -/* - * The programming guide specifies a full test of the on-board SRAM - * at initialization time. Undefine to remove this - */ -#define FULL_MEMORY_TEST - -/* - * This is the number of (4 byte) service entries that we will - * try to allocate at startup. Note that we will end up with - * one PAGE_SIZE's worth regardless of what this is set to - */ -#define SERVICE_ENTRIES (1024) -/* TODO: make above a module load-time option */ - -/* - * We normally read the onboard EEPROM in order to discover our MAC - * address. Undefine to _not_ do this - */ -/* #define READ_EEPROM */ /* ***DONT ENABLE YET*** */ -/* TODO: make above a module load-time option (also) */ - -/* - * Depth of TX fifo (in 128 byte units; range 2-31) - * Smaller numbers are better for network latency - * Larger numbers are better for PCI latency - * I'm really sure where the best tradeoff is, but the BSD driver uses - * 7 and it seems to work ok. - */ -#define TX_FIFO_DEPTH (7) -/* TODO: make above a module load-time option */ - -/* - * How often (in jiffies) we will try to unstick stuck connections - - * shouldn't need to happen much - */ -#define LANAI_POLL_PERIOD (10*HZ) -/* TODO: make above a module load-time option */ - -/* - * When allocating an AAL5 receiving buffer, try to make it at least - * large enough to hold this many max_sdu sized PDUs - */ -#define AAL5_RX_MULTIPLIER (3) -/* TODO: make above a module load-time option */ - -/* - * Same for transmitting buffer - */ -#define AAL5_TX_MULTIPLIER (3) -/* TODO: make above a module load-time option */ - -/* - * When allocating an AAL0 transmiting buffer, how many cells should fit. - * Remember we'll end up with a PAGE_SIZE of them anyway, so this isn't - * really critical - */ -#define AAL0_TX_MULTIPLIER (40) -/* TODO: make above a module load-time option */ - -/* - * How large should we make the AAL0 receiving buffer. Remember that this - * is shared between all AAL0 VC's - */ -#define AAL0_RX_BUFFER_SIZE (PAGE_SIZE) -/* TODO: make above a module load-time option */ - -/* - * Should we use Lanai's "powerdown" feature when no vcc's are bound? - */ -/* #define USE_POWERDOWN */ -/* TODO: make above a module load-time option (also) */ - -/* -------------------- DEBUGGING AIDS: */ - -#define DEV_LABEL "lanai" - -#ifdef DEBUG - -#define DPRINTK(format, args...) \ - printk(KERN_DEBUG DEV_LABEL ": " format, ##args) -#define APRINTK(truth, format, args...) \ - do { \ - if (unlikely(!(truth))) \ - printk(KERN_ERR DEV_LABEL ": " format, ##args); \ - } while (0) - -#else /* !DEBUG */ - -#define DPRINTK(format, args...) -#define APRINTK(truth, format, args...) - -#endif /* DEBUG */ - -#ifdef DEBUG_RW -#define RWDEBUG(format, args...) \ - printk(KERN_DEBUG DEV_LABEL ": " format, ##args) -#else /* !DEBUG_RW */ -#define RWDEBUG(format, args...) -#endif - -/* -------------------- DATA DEFINITIONS: */ - -#define LANAI_MAPPING_SIZE (0x40000) -#define LANAI_EEPROM_SIZE (128) - -typedef int vci_t; -typedef void __iomem *bus_addr_t; - -/* DMA buffer in host memory for TX, RX, or service list. */ -struct lanai_buffer { - u32 *start; /* From get_free_pages */ - u32 *end; /* One past last byte */ - u32 *ptr; /* Pointer to current host location */ - dma_addr_t dmaaddr; -}; - -struct lanai_vcc_stats { - unsigned rx_nomem; - union { - struct { - unsigned rx_badlen; - unsigned service_trash; - unsigned service_stream; - unsigned service_rxcrc; - } aal5; - struct { - } aal0; - } x; -}; - -struct lanai_dev; /* Forward declaration */ - -/* - * This is the card-specific per-vcc data. Note that unlike some other - * drivers there is NOT a 1-to-1 correspondance between these and - * atm_vcc's - each one of these represents an actual 2-way vcc, but - * an atm_vcc can be 1-way and share with a 1-way vcc in the other - * direction. To make it weirder, there can even be 0-way vccs - * bound to us, waiting to do a change_qos - */ -struct lanai_vcc { - bus_addr_t vbase; /* Base of VCC's registers */ - struct lanai_vcc_stats stats; - int nref; /* # of atm_vcc's who reference us */ - vci_t vci; - struct { - struct lanai_buffer buf; - struct atm_vcc *atmvcc; /* atm_vcc who is receiver */ - } rx; - struct { - struct lanai_buffer buf; - struct atm_vcc *atmvcc; /* atm_vcc who is transmitter */ - int endptr; /* last endptr from service entry */ - struct sk_buff_head backlog; - void (*unqueue)(struct lanai_dev *, struct lanai_vcc *, int); - } tx; -}; - -enum lanai_type { - lanai2 = PCI_DEVICE_ID_EF_ATM_LANAI2, - lanaihb = PCI_DEVICE_ID_EF_ATM_LANAIHB -}; - -struct lanai_dev_stats { - unsigned ovfl_trash; /* # of cells dropped - buffer overflow */ - unsigned vci_trash; /* # of cells dropped - closed vci */ - unsigned hec_err; /* # of cells dropped - bad HEC */ - unsigned atm_ovfl; /* # of cells dropped - rx fifo overflow */ - unsigned pcierr_parity_detect; - unsigned pcierr_serr_set; - unsigned pcierr_master_abort; - unsigned pcierr_m_target_abort; - unsigned pcierr_s_target_abort; - unsigned pcierr_master_parity; - unsigned service_notx; - unsigned service_norx; - unsigned service_rxnotaal5; - unsigned dma_reenable; - unsigned card_reset; -}; - -struct lanai_dev { - bus_addr_t base; - struct lanai_dev_stats stats; - struct lanai_buffer service; - struct lanai_vcc **vccs; -#ifdef USE_POWERDOWN - int nbound; /* number of bound vccs */ -#endif - enum lanai_type type; - vci_t num_vci; /* Currently just NUM_VCI */ - u8 eeprom[LANAI_EEPROM_SIZE]; - u32 serialno, magicno; - struct pci_dev *pci; - DECLARE_BITMAP(backlog_vccs, NUM_VCI); /* VCCs with tx backlog */ - DECLARE_BITMAP(transmit_ready, NUM_VCI); /* VCCs with transmit space */ - struct timer_list timer; - int naal0; - struct lanai_buffer aal0buf; /* AAL0 RX buffers */ - u32 conf1, conf2; /* CONFIG[12] registers */ - u32 status; /* STATUS register */ - spinlock_t endtxlock; - spinlock_t servicelock; - struct atm_vcc *cbrvcc; - int number; - int board_rev; -/* TODO - look at race conditions with maintence of conf1/conf2 */ -/* TODO - transmit locking: should we use _irq not _irqsave? */ -/* TODO - organize above in some rational fashion (see ) */ -}; - -/* - * Each device has two bitmaps for each VCC (baclog_vccs and transmit_ready) - * This function iterates one of these, calling a given function for each - * vci with their bit set - */ -static void vci_bitfield_iterate(struct lanai_dev *lanai, - const unsigned long *lp, - void (*func)(struct lanai_dev *,vci_t vci)) -{ - vci_t vci; - - for_each_set_bit(vci, lp, NUM_VCI) - func(lanai, vci); -} - -/* -------------------- BUFFER UTILITIES: */ - -/* - * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes - - * usually any page allocation will do. Just to be safe in case - * PAGE_SIZE is insanely tiny, though... - */ -#define LANAI_PAGE_SIZE ((PAGE_SIZE >= 1024) ? PAGE_SIZE : 1024) - -/* - * Allocate a buffer in host RAM for service list, RX, or TX - * Returns buf->start==NULL if no memory - * Note that the size will be rounded up 2^n bytes, and - * if we can't allocate that we'll settle for something smaller - * until minbytes - */ -static void lanai_buf_allocate(struct lanai_buffer *buf, - size_t bytes, size_t minbytes, struct pci_dev *pci) -{ - int size; - - if (bytes > (128 * 1024)) /* max lanai buffer size */ - bytes = 128 * 1024; - for (size = LANAI_PAGE_SIZE; size < bytes; size *= 2) - ; - if (minbytes < LANAI_PAGE_SIZE) - minbytes = LANAI_PAGE_SIZE; - do { - /* - * Technically we could use non-consistent mappings for - * everything, but the way the lanai uses DMA memory would - * make that a terrific pain. This is much simpler. - */ - buf->start = dma_alloc_coherent(&pci->dev, - size, &buf->dmaaddr, GFP_KERNEL); - if (buf->start != NULL) { /* Success */ - /* Lanai requires 256-byte alignment of DMA bufs */ - APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0, - "bad dmaaddr: 0x%lx\n", - (unsigned long) buf->dmaaddr); - buf->ptr = buf->start; - buf->end = (u32 *) - (&((unsigned char *) buf->start)[size]); - memset(buf->start, 0, size); - break; - } - size /= 2; - } while (size >= minbytes); -} - -/* size of buffer in bytes */ -static inline size_t lanai_buf_size(const struct lanai_buffer *buf) -{ - return ((unsigned long) buf->end) - ((unsigned long) buf->start); -} - -static void lanai_buf_deallocate(struct lanai_buffer *buf, - struct pci_dev *pci) -{ - if (buf->start != NULL) { - dma_free_coherent(&pci->dev, lanai_buf_size(buf), - buf->start, buf->dmaaddr); - buf->start = buf->end = buf->ptr = NULL; - } -} - -/* size of buffer as "card order" (0=1k .. 7=128k) */ -static int lanai_buf_size_cardorder(const struct lanai_buffer *buf) -{ - int order = get_order(lanai_buf_size(buf)) + (PAGE_SHIFT - 10); - - /* This can only happen if PAGE_SIZE is gigantic, but just in case */ - if (order > 7) - order = 7; - return order; -} - -/* -------------------- PORT I/O UTILITIES: */ - -/* Registers (and their bit-fields) */ -enum lanai_register { - Reset_Reg = 0x00, /* Reset; read for chip type; bits: */ -#define RESET_GET_BOARD_REV(x) (((x)>> 0)&0x03) /* Board revision */ -#define RESET_GET_BOARD_ID(x) (((x)>> 2)&0x03) /* Board ID */ -#define BOARD_ID_LANAI256 (0) /* 25.6M adapter card */ - Endian_Reg = 0x04, /* Endian setting */ - IntStatus_Reg = 0x08, /* Interrupt status */ - IntStatusMasked_Reg = 0x0C, /* Interrupt status (masked) */ - IntAck_Reg = 0x10, /* Interrupt acknowledge */ - IntAckMasked_Reg = 0x14, /* Interrupt acknowledge (masked) */ - IntStatusSet_Reg = 0x18, /* Get status + enable/disable */ - IntStatusSetMasked_Reg = 0x1C, /* Get status + en/di (masked) */ - IntControlEna_Reg = 0x20, /* Interrupt control enable */ - IntControlDis_Reg = 0x24, /* Interrupt control disable */ - Status_Reg = 0x28, /* Status */ -#define STATUS_PROMDATA (0x00000001) /* PROM_DATA pin */ -#define STATUS_WAITING (0x00000002) /* Interrupt being delayed */ -#define STATUS_SOOL (0x00000004) /* SOOL alarm */ -#define STATUS_LOCD (0x00000008) /* LOCD alarm */ -#define STATUS_LED (0x00000010) /* LED (HAPPI) output */ -#define STATUS_GPIN (0x00000020) /* GPIN pin */ -#define STATUS_BUTTBUSY (0x00000040) /* Butt register is pending */ - Config1_Reg = 0x2C, /* Config word 1; bits: */ -#define CONFIG1_PROMDATA (0x00000001) /* PROM_DATA pin */ -#define CONFIG1_PROMCLK (0x00000002) /* PROM_CLK pin */ -#define CONFIG1_SET_READMODE(x) ((x)*0x004) /* PCI BM reads; values: */ -#define READMODE_PLAIN (0) /* Plain memory read */ -#define READMODE_LINE (2) /* Memory read line */ -#define READMODE_MULTIPLE (3) /* Memory read multiple */ -#define CONFIG1_DMA_ENABLE (0x00000010) /* Turn on DMA */ -#define CONFIG1_POWERDOWN (0x00000020) /* Turn off clocks */ -#define CONFIG1_SET_LOOPMODE(x) ((x)*0x080) /* Clock&loop mode; values: */ -#define LOOPMODE_NORMAL (0) /* Normal - no loop */ -#define LOOPMODE_TIME (1) -#define LOOPMODE_DIAG (2) -#define LOOPMODE_LINE (3) -#define CONFIG1_MASK_LOOPMODE (0x00000180) -#define CONFIG1_SET_LEDMODE(x) ((x)*0x0200) /* Mode of LED; values: */ -#define LEDMODE_NOT_SOOL (0) /* !SOOL */ -#define LEDMODE_OFF (1) /* 0 */ -#define LEDMODE_ON (2) /* 1 */ -#define LEDMODE_NOT_LOCD (3) /* !LOCD */ -#define LEDMORE_GPIN (4) /* GPIN */ -#define LEDMODE_NOT_GPIN (7) /* !GPIN */ -#define CONFIG1_MASK_LEDMODE (0x00000E00) -#define CONFIG1_GPOUT1 (0x00001000) /* Toggle for reset */ -#define CONFIG1_GPOUT2 (0x00002000) /* Loopback PHY */ -#define CONFIG1_GPOUT3 (0x00004000) /* Loopback lanai */ - Config2_Reg = 0x30, /* Config word 2; bits: */ -#define CONFIG2_HOWMANY (0x00000001) /* >512 VCIs? */ -#define CONFIG2_PTI7_MODE (0x00000002) /* Make PTI=7 RM, not OAM */ -#define CONFIG2_VPI_CHK_DIS (0x00000004) /* Ignore RX VPI value */ -#define CONFIG2_HEC_DROP (0x00000008) /* Drop cells w/ HEC errors */ -#define CONFIG2_VCI0_NORMAL (0x00000010) /* Treat VCI=0 normally */ -#define CONFIG2_CBR_ENABLE (0x00000020) /* Deal with CBR traffic */ -#define CONFIG2_TRASH_ALL (0x00000040) /* Trashing incoming cells */ -#define CONFIG2_TX_DISABLE (0x00000080) /* Trashing outgoing cells */ -#define CONFIG2_SET_TRASH (0x00000100) /* Turn trashing on */ - Statistics_Reg = 0x34, /* Statistics; bits: */ -#define STATS_GET_FIFO_OVFL(x) (((x)>> 0)&0xFF) /* FIFO overflowed */ -#define STATS_GET_HEC_ERR(x) (((x)>> 8)&0xFF) /* HEC was bad */ -#define STATS_GET_BAD_VCI(x) (((x)>>16)&0xFF) /* VCI not open */ -#define STATS_GET_BUF_OVFL(x) (((x)>>24)&0xFF) /* VCC buffer full */ - ServiceStuff_Reg = 0x38, /* Service stuff; bits: */ -#define SSTUFF_SET_SIZE(x) ((x)*0x20000000) /* size of service buffer */ -#define SSTUFF_SET_ADDR(x) ((x)>>8) /* set address of buffer */ - ServWrite_Reg = 0x3C, /* ServWrite Pointer */ - ServRead_Reg = 0x40, /* ServRead Pointer */ - TxDepth_Reg = 0x44, /* FIFO Transmit Depth */ - Butt_Reg = 0x48, /* Butt register */ - CBR_ICG_Reg = 0x50, - CBR_PTR_Reg = 0x54, - PingCount_Reg = 0x58, /* Ping count */ - DMA_Addr_Reg = 0x5C /* DMA address */ -}; - -static inline bus_addr_t reg_addr(const struct lanai_dev *lanai, - enum lanai_register reg) -{ - return lanai->base + reg; -} - -static inline u32 reg_read(const struct lanai_dev *lanai, - enum lanai_register reg) -{ - u32 t; - t = readl(reg_addr(lanai, reg)); - RWDEBUG("R [0x%08X] 0x%02X = 0x%08X\n", (unsigned int) lanai->base, - (int) reg, t); - return t; -} - -static inline void reg_write(const struct lanai_dev *lanai, u32 val, - enum lanai_register reg) -{ - RWDEBUG("W [0x%08X] 0x%02X < 0x%08X\n", (unsigned int) lanai->base, - (int) reg, val); - writel(val, reg_addr(lanai, reg)); -} - -static inline void conf1_write(const struct lanai_dev *lanai) -{ - reg_write(lanai, lanai->conf1, Config1_Reg); -} - -static inline void conf2_write(const struct lanai_dev *lanai) -{ - reg_write(lanai, lanai->conf2, Config2_Reg); -} - -/* Same as conf2_write(), but defers I/O if we're powered down */ -static inline void conf2_write_if_powerup(const struct lanai_dev *lanai) -{ -#ifdef USE_POWERDOWN - if (unlikely((lanai->conf1 & CONFIG1_POWERDOWN) != 0)) - return; -#endif /* USE_POWERDOWN */ - conf2_write(lanai); -} - -static inline void reset_board(const struct lanai_dev *lanai) -{ - DPRINTK("about to reset board\n"); - reg_write(lanai, 0, Reset_Reg); - /* - * If we don't delay a little while here then we can end up - * leaving the card in a VERY weird state and lock up the - * PCI bus. This isn't documented anywhere but I've convinced - * myself after a lot of painful experimentation - */ - udelay(5); -} - -/* -------------------- CARD SRAM UTILITIES: */ - -/* The SRAM is mapped into normal PCI memory space - the only catch is - * that it is only 16-bits wide but must be accessed as 32-bit. The - * 16 high bits will be zero. We don't hide this, since they get - * programmed mostly like discrete registers anyway - */ -#define SRAM_START (0x20000) -#define SRAM_BYTES (0x20000) /* Again, half don't really exist */ - -static inline bus_addr_t sram_addr(const struct lanai_dev *lanai, int offset) -{ - return lanai->base + SRAM_START + offset; -} - -static inline u32 sram_read(const struct lanai_dev *lanai, int offset) -{ - return readl(sram_addr(lanai, offset)); -} - -static inline void sram_write(const struct lanai_dev *lanai, - u32 val, int offset) -{ - writel(val, sram_addr(lanai, offset)); -} - -static int sram_test_word(const struct lanai_dev *lanai, int offset, - u32 pattern) -{ - u32 readback; - sram_write(lanai, pattern, offset); - readback = sram_read(lanai, offset); - if (likely(readback == pattern)) - return 0; - printk(KERN_ERR DEV_LABEL - "(itf %d): SRAM word at %d bad: wrote 0x%X, read 0x%X\n", - lanai->number, offset, - (unsigned int) pattern, (unsigned int) readback); - return -EIO; -} - -static int sram_test_pass(const struct lanai_dev *lanai, u32 pattern) -{ - int offset, result = 0; - for (offset = 0; offset < SRAM_BYTES && result == 0; offset += 4) - result = sram_test_word(lanai, offset, pattern); - return result; -} - -static int sram_test_and_clear(const struct lanai_dev *lanai) -{ -#ifdef FULL_MEMORY_TEST - int result; - DPRINTK("testing SRAM\n"); - if ((result = sram_test_pass(lanai, 0x5555)) != 0) - return result; - if ((result = sram_test_pass(lanai, 0xAAAA)) != 0) - return result; -#endif - DPRINTK("clearing SRAM\n"); - return sram_test_pass(lanai, 0x0000); -} - -/* -------------------- CARD-BASED VCC TABLE UTILITIES: */ - -/* vcc table */ -enum lanai_vcc_offset { - vcc_rxaddr1 = 0x00, /* Location1, plus bits: */ -#define RXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of RX buffer */ -#define RXADDR1_SET_RMMODE(x) ((x)*0x00800) /* RM cell action; values: */ -#define RMMODE_TRASH (0) /* discard */ -#define RMMODE_PRESERVE (1) /* input as AAL0 */ -#define RMMODE_PIPE (2) /* pipe to coscheduler */ -#define RMMODE_PIPEALL (3) /* pipe non-RM too */ -#define RXADDR1_OAM_PRESERVE (0x00002000) /* Input OAM cells as AAL0 */ -#define RXADDR1_SET_MODE(x) ((x)*0x0004000) /* Reassembly mode */ -#define RXMODE_TRASH (0) /* discard */ -#define RXMODE_AAL0 (1) /* non-AAL5 mode */ -#define RXMODE_AAL5 (2) /* AAL5, intr. each PDU */ -#define RXMODE_AAL5_STREAM (3) /* AAL5 w/o per-PDU intr */ - vcc_rxaddr2 = 0x04, /* Location2 */ - vcc_rxcrc1 = 0x08, /* RX CRC claculation space */ - vcc_rxcrc2 = 0x0C, - vcc_rxwriteptr = 0x10, /* RX writeptr, plus bits: */ -#define RXWRITEPTR_LASTEFCI (0x00002000) /* Last PDU had EFCI bit */ -#define RXWRITEPTR_DROPPING (0x00004000) /* Had error, dropping */ -#define RXWRITEPTR_TRASHING (0x00008000) /* Trashing */ - vcc_rxbufstart = 0x14, /* RX bufstart, plus bits: */ -#define RXBUFSTART_CLP (0x00004000) -#define RXBUFSTART_CI (0x00008000) - vcc_rxreadptr = 0x18, /* RX readptr */ - vcc_txicg = 0x1C, /* TX ICG */ - vcc_txaddr1 = 0x20, /* Location1, plus bits: */ -#define TXADDR1_SET_SIZE(x) ((x)*0x0000100) /* size of TX buffer */ -#define TXADDR1_ABR (0x00008000) /* use ABR (doesn't work) */ - vcc_txaddr2 = 0x24, /* Location2 */ - vcc_txcrc1 = 0x28, /* TX CRC claculation space */ - vcc_txcrc2 = 0x2C, - vcc_txreadptr = 0x30, /* TX Readptr, plus bits: */ -#define TXREADPTR_GET_PTR(x) ((x)&0x01FFF) -#define TXREADPTR_MASK_DELTA (0x0000E000) /* ? */ - vcc_txendptr = 0x34, /* TX Endptr, plus bits: */ -#define TXENDPTR_CLP (0x00002000) -#define TXENDPTR_MASK_PDUMODE (0x0000C000) /* PDU mode; values: */ -#define PDUMODE_AAL0 (0*0x04000) -#define PDUMODE_AAL5 (2*0x04000) -#define PDUMODE_AAL5STREAM (3*0x04000) - vcc_txwriteptr = 0x38, /* TX Writeptr */ -#define TXWRITEPTR_GET_PTR(x) ((x)&0x1FFF) - vcc_txcbr_next = 0x3C /* # of next CBR VCI in ring */ -#define TXCBR_NEXT_BOZO (0x00008000) /* "bozo bit" */ -}; - -#define CARDVCC_SIZE (0x40) - -static inline bus_addr_t cardvcc_addr(const struct lanai_dev *lanai, - vci_t vci) -{ - return sram_addr(lanai, vci * CARDVCC_SIZE); -} - -static inline u32 cardvcc_read(const struct lanai_vcc *lvcc, - enum lanai_vcc_offset offset) -{ - u32 val; - APRINTK(lvcc->vbase != NULL, "cardvcc_read: unbound vcc!\n"); - val= readl(lvcc->vbase + offset); - RWDEBUG("VR vci=%04d 0x%02X = 0x%08X\n", - lvcc->vci, (int) offset, val); - return val; -} - -static inline void cardvcc_write(const struct lanai_vcc *lvcc, - u32 val, enum lanai_vcc_offset offset) -{ - APRINTK(lvcc->vbase != NULL, "cardvcc_write: unbound vcc!\n"); - APRINTK((val & ~0xFFFF) == 0, - "cardvcc_write: bad val 0x%X (vci=%d, addr=0x%02X)\n", - (unsigned int) val, lvcc->vci, (unsigned int) offset); - RWDEBUG("VW vci=%04d 0x%02X > 0x%08X\n", - lvcc->vci, (unsigned int) offset, (unsigned int) val); - writel(val, lvcc->vbase + offset); -} - -/* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */ - -/* How many bytes will an AAL5 PDU take to transmit - remember that: - * o we need to add 8 bytes for length, CPI, UU, and CRC - * o we need to round up to 48 bytes for cells - */ -static inline int aal5_size(int size) -{ - int cells = (size + 8 + 47) / 48; - return cells * 48; -} - -/* -------------------- FREE AN ATM SKB: */ - -static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb) -{ - if (atmvcc->pop != NULL) - atmvcc->pop(atmvcc, skb); - else - dev_kfree_skb_any(skb); -} - -/* -------------------- TURN VCCS ON AND OFF: */ - -static void host_vcc_start_rx(const struct lanai_vcc *lvcc) -{ - u32 addr1; - if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) { - dma_addr_t dmaaddr = lvcc->rx.buf.dmaaddr; - cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1); - cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2); - cardvcc_write(lvcc, 0, vcc_rxwriteptr); - cardvcc_write(lvcc, 0, vcc_rxbufstart); - cardvcc_write(lvcc, 0, vcc_rxreadptr); - cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_rxaddr2); - addr1 = ((dmaaddr >> 8) & 0xFF) | - RXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->rx.buf))| - RXADDR1_SET_RMMODE(RMMODE_TRASH) | /* ??? */ - /* RXADDR1_OAM_PRESERVE | --- no OAM support yet */ - RXADDR1_SET_MODE(RXMODE_AAL5); - } else - addr1 = RXADDR1_SET_RMMODE(RMMODE_PRESERVE) | /* ??? */ - RXADDR1_OAM_PRESERVE | /* ??? */ - RXADDR1_SET_MODE(RXMODE_AAL0); - /* This one must be last! */ - cardvcc_write(lvcc, addr1, vcc_rxaddr1); -} - -static void host_vcc_start_tx(const struct lanai_vcc *lvcc) -{ - dma_addr_t dmaaddr = lvcc->tx.buf.dmaaddr; - cardvcc_write(lvcc, 0, vcc_txicg); - cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1); - cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2); - cardvcc_write(lvcc, 0, vcc_txreadptr); - cardvcc_write(lvcc, 0, vcc_txendptr); - cardvcc_write(lvcc, 0, vcc_txwriteptr); - cardvcc_write(lvcc, - (lvcc->tx.atmvcc->qos.txtp.traffic_class == ATM_CBR) ? - TXCBR_NEXT_BOZO | lvcc->vci : 0, vcc_txcbr_next); - cardvcc_write(lvcc, (dmaaddr >> 16) & 0xFFFF, vcc_txaddr2); - cardvcc_write(lvcc, - ((dmaaddr >> 8) & 0xFF) | - TXADDR1_SET_SIZE(lanai_buf_size_cardorder(&lvcc->tx.buf)), - vcc_txaddr1); -} - -/* Shutdown receiving on card */ -static void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc) -{ - if (lvcc->vbase == NULL) /* We were never bound to a VCI */ - return; - /* 15.1.1 - set to trashing, wait one cell time (15us) */ - cardvcc_write(lvcc, - RXADDR1_SET_RMMODE(RMMODE_TRASH) | - RXADDR1_SET_MODE(RXMODE_TRASH), vcc_rxaddr1); - udelay(15); - /* 15.1.2 - clear rest of entries */ - cardvcc_write(lvcc, 0, vcc_rxaddr2); - cardvcc_write(lvcc, 0, vcc_rxcrc1); - cardvcc_write(lvcc, 0, vcc_rxcrc2); - cardvcc_write(lvcc, 0, vcc_rxwriteptr); - cardvcc_write(lvcc, 0, vcc_rxbufstart); - cardvcc_write(lvcc, 0, vcc_rxreadptr); -} - -/* Shutdown transmitting on card. - * Unfortunately the lanai needs us to wait until all the data - * drains out of the buffer before we can dealloc it, so this - * can take a while -- up to 370ms for a full 128KB buffer - * assuming everone else is quiet. In theory the time is - * boundless if there's a CBR VCC holding things up. - */ -static void lanai_shutdown_tx_vci(struct lanai_dev *lanai, - struct lanai_vcc *lvcc) -{ - struct sk_buff *skb; - unsigned long flags, timeout; - int read, write, lastread = -1; - - if (lvcc->vbase == NULL) /* We were never bound to a VCI */ - return; - /* 15.2.1 - wait for queue to drain */ - while ((skb = skb_dequeue(&lvcc->tx.backlog)) != NULL) - lanai_free_skb(lvcc->tx.atmvcc, skb); - read_lock_irqsave(&vcc_sklist_lock, flags); - __clear_bit(lvcc->vci, lanai->backlog_vccs); - read_unlock_irqrestore(&vcc_sklist_lock, flags); - /* - * We need to wait for the VCC to drain but don't wait forever. We - * give each 1K of buffer size 1/128th of a second to clear out. - * TODO: maybe disable CBR if we're about to timeout? - */ - timeout = jiffies + - (((lanai_buf_size(&lvcc->tx.buf) / 1024) * HZ) >> 7); - write = TXWRITEPTR_GET_PTR(cardvcc_read(lvcc, vcc_txwriteptr)); - for (;;) { - read = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); - if (read == write && /* Is TX buffer empty? */ - (lvcc->tx.atmvcc->qos.txtp.traffic_class != ATM_CBR || - (cardvcc_read(lvcc, vcc_txcbr_next) & - TXCBR_NEXT_BOZO) == 0)) - break; - if (read != lastread) { /* Has there been any progress? */ - lastread = read; - timeout += HZ / 10; - } - if (unlikely(time_after(jiffies, timeout))) { - printk(KERN_ERR DEV_LABEL "(itf %d): Timed out on " - "backlog closing vci %d\n", - lvcc->tx.atmvcc->dev->number, lvcc->vci); - DPRINTK("read, write = %d, %d\n", read, write); - break; - } - msleep(40); - } - /* 15.2.2 - clear out all tx registers */ - cardvcc_write(lvcc, 0, vcc_txreadptr); - cardvcc_write(lvcc, 0, vcc_txwriteptr); - cardvcc_write(lvcc, 0, vcc_txendptr); - cardvcc_write(lvcc, 0, vcc_txcrc1); - cardvcc_write(lvcc, 0, vcc_txcrc2); - cardvcc_write(lvcc, 0, vcc_txaddr2); - cardvcc_write(lvcc, 0, vcc_txaddr1); -} - -/* -------------------- MANAGING AAL0 RX BUFFER: */ - -static inline int aal0_buffer_allocate(struct lanai_dev *lanai) -{ - DPRINTK("aal0_buffer_allocate: allocating AAL0 RX buffer\n"); - lanai_buf_allocate(&lanai->aal0buf, AAL0_RX_BUFFER_SIZE, 80, - lanai->pci); - return (lanai->aal0buf.start == NULL) ? -ENOMEM : 0; -} - -static inline void aal0_buffer_free(struct lanai_dev *lanai) -{ - DPRINTK("aal0_buffer_allocate: freeing AAL0 RX buffer\n"); - lanai_buf_deallocate(&lanai->aal0buf, lanai->pci); -} - -/* -------------------- EEPROM UTILITIES: */ - -/* Offsets of data in the EEPROM */ -#define EEPROM_COPYRIGHT (0) -#define EEPROM_COPYRIGHT_LEN (44) -#define EEPROM_CHECKSUM (62) -#define EEPROM_CHECKSUM_REV (63) -#define EEPROM_MAC (64) -#define EEPROM_MAC_REV (70) -#define EEPROM_SERIAL (112) -#define EEPROM_SERIAL_REV (116) -#define EEPROM_MAGIC (120) -#define EEPROM_MAGIC_REV (124) - -#define EEPROM_MAGIC_VALUE (0x5AB478D2) - -#ifndef READ_EEPROM - -/* Stub functions to use if EEPROM reading is disabled */ -static int eeprom_read(struct lanai_dev *lanai) -{ - printk(KERN_INFO DEV_LABEL "(itf %d): *NOT* reading EEPROM\n", - lanai->number); - memset(&lanai->eeprom[EEPROM_MAC], 0, 6); - return 0; -} - -static int eeprom_validate(struct lanai_dev *lanai) -{ - lanai->serialno = 0; - lanai->magicno = EEPROM_MAGIC_VALUE; - return 0; -} - -#else /* READ_EEPROM */ - -static int eeprom_read(struct lanai_dev *lanai) -{ - int i, address; - u8 data; - u32 tmp; -#define set_config1(x) do { lanai->conf1 = x; conf1_write(lanai); \ - } while (0) -#define clock_h() set_config1(lanai->conf1 | CONFIG1_PROMCLK) -#define clock_l() set_config1(lanai->conf1 &~ CONFIG1_PROMCLK) -#define data_h() set_config1(lanai->conf1 | CONFIG1_PROMDATA) -#define data_l() set_config1(lanai->conf1 &~ CONFIG1_PROMDATA) -#define pre_read() do { data_h(); clock_h(); udelay(5); } while (0) -#define read_pin() (reg_read(lanai, Status_Reg) & STATUS_PROMDATA) -#define send_stop() do { data_l(); udelay(5); clock_h(); udelay(5); \ - data_h(); udelay(5); } while (0) - /* start with both clock and data high */ - data_h(); clock_h(); udelay(5); - for (address = 0; address < LANAI_EEPROM_SIZE; address++) { - data = (address << 1) | 1; /* Command=read + address */ - /* send start bit */ - data_l(); udelay(5); - clock_l(); udelay(5); - for (i = 128; i != 0; i >>= 1) { /* write command out */ - tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) | - ((data & i) ? CONFIG1_PROMDATA : 0); - if (lanai->conf1 != tmp) { - set_config1(tmp); - udelay(5); /* Let new data settle */ - } - clock_h(); udelay(5); clock_l(); udelay(5); - } - /* look for ack */ - data_h(); clock_h(); udelay(5); - if (read_pin() != 0) - goto error; /* No ack seen */ - clock_l(); udelay(5); - /* read back result */ - for (data = 0, i = 7; i >= 0; i--) { - data_h(); clock_h(); udelay(5); - data = (data << 1) | !!read_pin(); - clock_l(); udelay(5); - } - /* look again for ack */ - data_h(); clock_h(); udelay(5); - if (read_pin() == 0) - goto error; /* Spurious ack */ - clock_l(); udelay(5); - send_stop(); - lanai->eeprom[address] = data; - DPRINTK("EEPROM 0x%04X %02X\n", - (unsigned int) address, (unsigned int) data); - } - return 0; - error: - clock_l(); udelay(5); /* finish read */ - send_stop(); - printk(KERN_ERR DEV_LABEL "(itf %d): error reading EEPROM byte %d\n", - lanai->number, address); - return -EIO; -#undef set_config1 -#undef clock_h -#undef clock_l -#undef data_h -#undef data_l -#undef pre_read -#undef read_pin -#undef send_stop -} - -/* read a big-endian 4-byte value out of eeprom */ -static inline u32 eeprom_be4(const struct lanai_dev *lanai, int address) -{ - return be32_to_cpup((const u32 *) &lanai->eeprom[address]); -} - -/* Checksum/validate EEPROM contents */ -static int eeprom_validate(struct lanai_dev *lanai) -{ - int i, s; - u32 v; - const u8 *e = lanai->eeprom; -#ifdef DEBUG - /* First, see if we can get an ASCIIZ string out of the copyright */ - for (i = EEPROM_COPYRIGHT; - i < (EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN); i++) - if (e[i] < 0x20 || e[i] > 0x7E) - break; - if ( i != EEPROM_COPYRIGHT && - i != EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN && e[i] == '\0') - DPRINTK("eeprom: copyright = \"%s\"\n", - (char *) &e[EEPROM_COPYRIGHT]); - else - DPRINTK("eeprom: copyright not found\n"); -#endif - /* Validate checksum */ - for (i = s = 0; i < EEPROM_CHECKSUM; i++) - s += e[i]; - s &= 0xFF; - if (s != e[EEPROM_CHECKSUM]) { - printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM checksum bad " - "(wanted 0x%02X, got 0x%02X)\n", lanai->number, - (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM]); - return -EIO; - } - s ^= 0xFF; - if (s != e[EEPROM_CHECKSUM_REV]) { - printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM inverse checksum " - "bad (wanted 0x%02X, got 0x%02X)\n", lanai->number, - (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM_REV]); - return -EIO; - } - /* Verify MAC address */ - for (i = 0; i < 6; i++) - if ((e[EEPROM_MAC + i] ^ e[EEPROM_MAC_REV + i]) != 0xFF) { - printk(KERN_ERR DEV_LABEL - "(itf %d) : EEPROM MAC addresses don't match " - "(0x%02X, inverse 0x%02X)\n", lanai->number, - (unsigned int) e[EEPROM_MAC + i], - (unsigned int) e[EEPROM_MAC_REV + i]); - return -EIO; - } - DPRINTK("eeprom: MAC address = %pM\n", &e[EEPROM_MAC]); - /* Verify serial number */ - lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL); - v = eeprom_be4(lanai, EEPROM_SERIAL_REV); - if ((lanai->serialno ^ v) != 0xFFFFFFFF) { - printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM serial numbers " - "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, - (unsigned int) lanai->serialno, (unsigned int) v); - return -EIO; - } - DPRINTK("eeprom: Serial number = %d\n", (unsigned int) lanai->serialno); - /* Verify magic number */ - lanai->magicno = eeprom_be4(lanai, EEPROM_MAGIC); - v = eeprom_be4(lanai, EEPROM_MAGIC_REV); - if ((lanai->magicno ^ v) != 0xFFFFFFFF) { - printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM magic numbers " - "don't match (0x%08X, inverse 0x%08X)\n", lanai->number, - lanai->magicno, v); - return -EIO; - } - DPRINTK("eeprom: Magic number = 0x%08X\n", lanai->magicno); - if (lanai->magicno != EEPROM_MAGIC_VALUE) - printk(KERN_WARNING DEV_LABEL "(itf %d): warning - EEPROM " - "magic not what expected (got 0x%08X, not 0x%08X)\n", - lanai->number, (unsigned int) lanai->magicno, - (unsigned int) EEPROM_MAGIC_VALUE); - return 0; -} - -#endif /* READ_EEPROM */ - -static inline const u8 *eeprom_mac(const struct lanai_dev *lanai) -{ - return &lanai->eeprom[EEPROM_MAC]; -} - -/* -------------------- INTERRUPT HANDLING UTILITIES: */ - -/* Interrupt types */ -#define INT_STATS (0x00000002) /* Statistics counter overflow */ -#define INT_SOOL (0x00000004) /* SOOL changed state */ -#define INT_LOCD (0x00000008) /* LOCD changed state */ -#define INT_LED (0x00000010) /* LED (HAPPI) changed state */ -#define INT_GPIN (0x00000020) /* GPIN changed state */ -#define INT_PING (0x00000040) /* PING_COUNT fulfilled */ -#define INT_WAKE (0x00000080) /* Lanai wants bus */ -#define INT_CBR0 (0x00000100) /* CBR sched hit VCI 0 */ -#define INT_LOCK (0x00000200) /* Service list overflow */ -#define INT_MISMATCH (0x00000400) /* TX magic list mismatch */ -#define INT_AAL0_STR (0x00000800) /* Non-AAL5 buffer half filled */ -#define INT_AAL0 (0x00001000) /* Non-AAL5 data available */ -#define INT_SERVICE (0x00002000) /* Service list entries available */ -#define INT_TABORTSENT (0x00004000) /* Target abort sent by lanai */ -#define INT_TABORTBM (0x00008000) /* Abort rcv'd as bus master */ -#define INT_TIMEOUTBM (0x00010000) /* No response to bus master */ -#define INT_PCIPARITY (0x00020000) /* Parity error on PCI */ - -/* Sets of the above */ -#define INT_ALL (0x0003FFFE) /* All interrupts */ -#define INT_STATUS (0x0000003C) /* Some status pin changed */ -#define INT_DMASHUT (0x00038000) /* DMA engine got shut down */ -#define INT_SEGSHUT (0x00000700) /* Segmentation got shut down */ - -static inline u32 intr_pending(const struct lanai_dev *lanai) -{ - return reg_read(lanai, IntStatusMasked_Reg); -} - -static inline void intr_enable(const struct lanai_dev *lanai, u32 i) -{ - reg_write(lanai, i, IntControlEna_Reg); -} - -static inline void intr_disable(const struct lanai_dev *lanai, u32 i) -{ - reg_write(lanai, i, IntControlDis_Reg); -} - -/* -------------------- CARD/PCI STATUS: */ - -static void status_message(int itf, const char *name, int status) -{ - static const char *onoff[2] = { "off to on", "on to off" }; - printk(KERN_INFO DEV_LABEL "(itf %d): %s changed from %s\n", - itf, name, onoff[!status]); -} - -static void lanai_check_status(struct lanai_dev *lanai) -{ - u32 new = reg_read(lanai, Status_Reg); - u32 changes = new ^ lanai->status; - lanai->status = new; -#define e(flag, name) \ - if (changes & flag) \ - status_message(lanai->number, name, new & flag) - e(STATUS_SOOL, "SOOL"); - e(STATUS_LOCD, "LOCD"); - e(STATUS_LED, "LED"); - e(STATUS_GPIN, "GPIN"); -#undef e -} - -static void pcistatus_got(int itf, const char *name) -{ - printk(KERN_INFO DEV_LABEL "(itf %d): PCI got %s error\n", itf, name); -} - -static void pcistatus_check(struct lanai_dev *lanai, int clearonly) -{ - u16 s; - int result; - result = pci_read_config_word(lanai->pci, PCI_STATUS, &s); - if (result != PCIBIOS_SUCCESSFUL) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't read PCI_STATUS: " - "%d\n", lanai->number, result); - return; - } - s &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | - PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT | - PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_PARITY; - if (s == 0) - return; - result = pci_write_config_word(lanai->pci, PCI_STATUS, s); - if (result != PCIBIOS_SUCCESSFUL) - printk(KERN_ERR DEV_LABEL "(itf %d): can't write PCI_STATUS: " - "%d\n", lanai->number, result); - if (clearonly) - return; -#define e(flag, name, stat) \ - if (s & flag) { \ - pcistatus_got(lanai->number, name); \ - ++lanai->stats.pcierr_##stat; \ - } - e(PCI_STATUS_DETECTED_PARITY, "parity", parity_detect); - e(PCI_STATUS_SIG_SYSTEM_ERROR, "signalled system", serr_set); - e(PCI_STATUS_REC_MASTER_ABORT, "master", master_abort); - e(PCI_STATUS_REC_TARGET_ABORT, "master target", m_target_abort); - e(PCI_STATUS_SIG_TARGET_ABORT, "slave", s_target_abort); - e(PCI_STATUS_PARITY, "master parity", master_parity); -#undef e -} - -/* -------------------- VCC TX BUFFER UTILITIES: */ - -/* space left in tx buffer in bytes */ -static inline int vcc_tx_space(const struct lanai_vcc *lvcc, int endptr) -{ - int r; - r = endptr * 16; - r -= ((unsigned long) lvcc->tx.buf.ptr) - - ((unsigned long) lvcc->tx.buf.start); - r -= 16; /* Leave "bubble" - if start==end it looks empty */ - if (r < 0) - r += lanai_buf_size(&lvcc->tx.buf); - return r; -} - -/* test if VCC is currently backlogged */ -static inline int vcc_is_backlogged(const struct lanai_vcc *lvcc) -{ - return !skb_queue_empty(&lvcc->tx.backlog); -} - -/* Bit fields in the segmentation buffer descriptor */ -#define DESCRIPTOR_MAGIC (0xD0000000) -#define DESCRIPTOR_AAL5 (0x00008000) -#define DESCRIPTOR_AAL5_STREAM (0x00004000) -#define DESCRIPTOR_CLP (0x00002000) - -/* Add 32-bit descriptor with its padding */ -static inline void vcc_tx_add_aal5_descriptor(struct lanai_vcc *lvcc, - u32 flags, int len) -{ - int pos; - APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 0, - "vcc_tx_add_aal5_descriptor: bad ptr=%p\n", lvcc->tx.buf.ptr); - lvcc->tx.buf.ptr += 4; /* Hope the values REALLY don't matter */ - pos = ((unsigned char *) lvcc->tx.buf.ptr) - - (unsigned char *) lvcc->tx.buf.start; - APRINTK((pos & ~0x0001FFF0) == 0, - "vcc_tx_add_aal5_descriptor: bad pos (%d) before, vci=%d, " - "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci, - lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end); - pos = (pos + len) & (lanai_buf_size(&lvcc->tx.buf) - 1); - APRINTK((pos & ~0x0001FFF0) == 0, - "vcc_tx_add_aal5_descriptor: bad pos (%d) after, vci=%d, " - "start,ptr,end=%p,%p,%p\n", pos, lvcc->vci, - lvcc->tx.buf.start, lvcc->tx.buf.ptr, lvcc->tx.buf.end); - lvcc->tx.buf.ptr[-1] = - cpu_to_le32(DESCRIPTOR_MAGIC | DESCRIPTOR_AAL5 | - ((lvcc->tx.atmvcc->atm_options & ATM_ATMOPT_CLP) ? - DESCRIPTOR_CLP : 0) | flags | pos >> 4); - if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end) - lvcc->tx.buf.ptr = lvcc->tx.buf.start; -} - -/* Add 32-bit AAL5 trailer and leave room for its CRC */ -static inline void vcc_tx_add_aal5_trailer(struct lanai_vcc *lvcc, - int len, int cpi, int uu) -{ - APRINTK((((unsigned long) lvcc->tx.buf.ptr) & 15) == 8, - "vcc_tx_add_aal5_trailer: bad ptr=%p\n", lvcc->tx.buf.ptr); - lvcc->tx.buf.ptr += 2; - lvcc->tx.buf.ptr[-2] = cpu_to_be32((uu << 24) | (cpi << 16) | len); - if (lvcc->tx.buf.ptr >= lvcc->tx.buf.end) - lvcc->tx.buf.ptr = lvcc->tx.buf.start; -} - -static inline void vcc_tx_memcpy(struct lanai_vcc *lvcc, - const unsigned char *src, int n) -{ - unsigned char *e; - int m; - e = ((unsigned char *) lvcc->tx.buf.ptr) + n; - m = e - (unsigned char *) lvcc->tx.buf.end; - if (m < 0) - m = 0; - memcpy(lvcc->tx.buf.ptr, src, n - m); - if (m != 0) { - memcpy(lvcc->tx.buf.start, src + n - m, m); - e = ((unsigned char *) lvcc->tx.buf.start) + m; - } - lvcc->tx.buf.ptr = (u32 *) e; -} - -static inline void vcc_tx_memzero(struct lanai_vcc *lvcc, int n) -{ - unsigned char *e; - int m; - if (n == 0) - return; - e = ((unsigned char *) lvcc->tx.buf.ptr) + n; - m = e - (unsigned char *) lvcc->tx.buf.end; - if (m < 0) - m = 0; - memset(lvcc->tx.buf.ptr, 0, n - m); - if (m != 0) { - memset(lvcc->tx.buf.start, 0, m); - e = ((unsigned char *) lvcc->tx.buf.start) + m; - } - lvcc->tx.buf.ptr = (u32 *) e; -} - -/* Update "butt" register to specify new WritePtr */ -static inline void lanai_endtx(struct lanai_dev *lanai, - const struct lanai_vcc *lvcc) -{ - int i, ptr = ((unsigned char *) lvcc->tx.buf.ptr) - - (unsigned char *) lvcc->tx.buf.start; - APRINTK((ptr & ~0x0001FFF0) == 0, - "lanai_endtx: bad ptr (%d), vci=%d, start,ptr,end=%p,%p,%p\n", - ptr, lvcc->vci, lvcc->tx.buf.start, lvcc->tx.buf.ptr, - lvcc->tx.buf.end); - - /* - * Since the "butt register" is a shared resounce on the card we - * serialize all accesses to it through this spinlock. This is - * mostly just paranoia since the register is rarely "busy" anyway - * but is needed for correctness. - */ - spin_lock(&lanai->endtxlock); - /* - * We need to check if the "butt busy" bit is set before - * updating the butt register. In theory this should - * never happen because the ATM card is plenty fast at - * updating the register. Still, we should make sure - */ - for (i = 0; reg_read(lanai, Status_Reg) & STATUS_BUTTBUSY; i++) { - if (unlikely(i > 50)) { - printk(KERN_ERR DEV_LABEL "(itf %d): butt register " - "always busy!\n", lanai->number); - break; - } - udelay(5); - } - /* - * Before we tall the card to start work we need to be sure 100% of - * the info in the service buffer has been written before we tell - * the card about it - */ - wmb(); - reg_write(lanai, (ptr << 12) | lvcc->vci, Butt_Reg); - spin_unlock(&lanai->endtxlock); -} - -/* - * Add one AAL5 PDU to lvcc's transmit buffer. Caller garauntees there's - * space available. "pdusize" is the number of bytes the PDU will take - */ -static void lanai_send_one_aal5(struct lanai_dev *lanai, - struct lanai_vcc *lvcc, struct sk_buff *skb, int pdusize) -{ - int pad; - APRINTK(pdusize == aal5_size(skb->len), - "lanai_send_one_aal5: wrong size packet (%d != %d)\n", - pdusize, aal5_size(skb->len)); - vcc_tx_add_aal5_descriptor(lvcc, 0, pdusize); - pad = pdusize - skb->len - 8; - APRINTK(pad >= 0, "pad is negative (%d)\n", pad); - APRINTK(pad < 48, "pad is too big (%d)\n", pad); - vcc_tx_memcpy(lvcc, skb->data, skb->len); - vcc_tx_memzero(lvcc, pad); - vcc_tx_add_aal5_trailer(lvcc, skb->len, 0, 0); - lanai_endtx(lanai, lvcc); - lanai_free_skb(lvcc->tx.atmvcc, skb); - atomic_inc(&lvcc->tx.atmvcc->stats->tx); -} - -/* Try to fill the buffer - don't call unless there is backlog */ -static void vcc_tx_unqueue_aal5(struct lanai_dev *lanai, - struct lanai_vcc *lvcc, int endptr) -{ - int n; - struct sk_buff *skb; - int space = vcc_tx_space(lvcc, endptr); - APRINTK(vcc_is_backlogged(lvcc), - "vcc_tx_unqueue() called with empty backlog (vci=%d)\n", - lvcc->vci); - while (space >= 64) { - skb = skb_dequeue(&lvcc->tx.backlog); - if (skb == NULL) - goto no_backlog; - n = aal5_size(skb->len); - if (n + 16 > space) { - /* No room for this packet - put it back on queue */ - skb_queue_head(&lvcc->tx.backlog, skb); - return; - } - lanai_send_one_aal5(lanai, lvcc, skb, n); - space -= n + 16; - } - if (!vcc_is_backlogged(lvcc)) { - no_backlog: - __clear_bit(lvcc->vci, lanai->backlog_vccs); - } -} - -/* Given an skb that we want to transmit either send it now or queue */ -static void vcc_tx_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc, - struct sk_buff *skb) -{ - int space, n; - if (vcc_is_backlogged(lvcc)) /* Already backlogged */ - goto queue_it; - space = vcc_tx_space(lvcc, - TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr))); - n = aal5_size(skb->len); - APRINTK(n + 16 >= 64, "vcc_tx_aal5: n too small (%d)\n", n); - if (space < n + 16) { /* No space for this PDU */ - __set_bit(lvcc->vci, lanai->backlog_vccs); - queue_it: - skb_queue_tail(&lvcc->tx.backlog, skb); - return; - } - lanai_send_one_aal5(lanai, lvcc, skb, n); -} - -static void vcc_tx_unqueue_aal0(struct lanai_dev *lanai, - struct lanai_vcc *lvcc, int endptr) -{ - printk(KERN_INFO DEV_LABEL - ": vcc_tx_unqueue_aal0: not implemented\n"); -} - -static void vcc_tx_aal0(struct lanai_dev *lanai, struct lanai_vcc *lvcc, - struct sk_buff *skb) -{ - printk(KERN_INFO DEV_LABEL ": vcc_tx_aal0: not implemented\n"); - /* Remember to increment lvcc->tx.atmvcc->stats->tx */ - lanai_free_skb(lvcc->tx.atmvcc, skb); -} - -/* -------------------- VCC RX BUFFER UTILITIES: */ - -/* unlike the _tx_ cousins, this doesn't update ptr */ -static inline void vcc_rx_memcpy(unsigned char *dest, - const struct lanai_vcc *lvcc, int n) -{ - int m = ((const unsigned char *) lvcc->rx.buf.ptr) + n - - ((const unsigned char *) (lvcc->rx.buf.end)); - if (m < 0) - m = 0; - memcpy(dest, lvcc->rx.buf.ptr, n - m); - memcpy(dest + n - m, lvcc->rx.buf.start, m); - /* Make sure that these copies don't get reordered */ - barrier(); -} - -/* Receive AAL5 data on a VCC with a particular endptr */ -static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr) -{ - int size; - struct sk_buff *skb; - const u32 *x; - u32 *end = &lvcc->rx.buf.start[endptr * 4]; - int n = ((unsigned long) end) - ((unsigned long) lvcc->rx.buf.ptr); - if (n < 0) - n += lanai_buf_size(&lvcc->rx.buf); - APRINTK(n >= 0 && n < lanai_buf_size(&lvcc->rx.buf) && !(n & 15), - "vcc_rx_aal5: n out of range (%d/%zu)\n", - n, lanai_buf_size(&lvcc->rx.buf)); - /* Recover the second-to-last word to get true pdu length */ - if ((x = &end[-2]) < lvcc->rx.buf.start) - x = &lvcc->rx.buf.end[-2]; - /* - * Before we actually read from the buffer, make sure the memory - * changes have arrived - */ - rmb(); - size = be32_to_cpup(x) & 0xffff; - if (unlikely(n != aal5_size(size))) { - /* Make sure size matches padding */ - printk(KERN_INFO DEV_LABEL "(itf %d): Got bad AAL5 length " - "on vci=%d - size=%d n=%d\n", - lvcc->rx.atmvcc->dev->number, lvcc->vci, size, n); - lvcc->stats.x.aal5.rx_badlen++; - goto out; - } - skb = atm_alloc_charge(lvcc->rx.atmvcc, size, GFP_ATOMIC); - if (unlikely(skb == NULL)) { - lvcc->stats.rx_nomem++; - goto out; - } - skb_put(skb, size); - vcc_rx_memcpy(skb->data, lvcc, size); - ATM_SKB(skb)->vcc = lvcc->rx.atmvcc; - __net_timestamp(skb); - lvcc->rx.atmvcc->push(lvcc->rx.atmvcc, skb); - atomic_inc(&lvcc->rx.atmvcc->stats->rx); - out: - lvcc->rx.buf.ptr = end; - cardvcc_write(lvcc, endptr, vcc_rxreadptr); -} - -static void vcc_rx_aal0(struct lanai_dev *lanai) -{ - printk(KERN_INFO DEV_LABEL ": vcc_rx_aal0: not implemented\n"); - /* Remember to get read_lock(&vcc_sklist_lock) while looking up VC */ - /* Remember to increment lvcc->rx.atmvcc->stats->rx */ -} - -/* -------------------- MANAGING HOST-BASED VCC TABLE: */ - -/* Decide whether to use vmalloc or get_zeroed_page for VCC table */ -#if (NUM_VCI * BITS_PER_LONG) <= PAGE_SIZE -#define VCCTABLE_GETFREEPAGE -#else -#include -#endif - -static int vcc_table_allocate(struct lanai_dev *lanai) -{ -#ifdef VCCTABLE_GETFREEPAGE - APRINTK((lanai->num_vci) * sizeof(struct lanai_vcc *) <= PAGE_SIZE, - "vcc table > PAGE_SIZE!"); - lanai->vccs = (struct lanai_vcc **) get_zeroed_page(GFP_KERNEL); - return (lanai->vccs == NULL) ? -ENOMEM : 0; -#else - int bytes = (lanai->num_vci) * sizeof(struct lanai_vcc *); - lanai->vccs = vzalloc(bytes); - if (unlikely(lanai->vccs == NULL)) - return -ENOMEM; - return 0; -#endif -} - -static inline void vcc_table_deallocate(const struct lanai_dev *lanai) -{ -#ifdef VCCTABLE_GETFREEPAGE - free_page((unsigned long) lanai->vccs); -#else - vfree(lanai->vccs); -#endif -} - -/* Allocate a fresh lanai_vcc, with the appropriate things cleared */ -static inline struct lanai_vcc *new_lanai_vcc(void) -{ - struct lanai_vcc *lvcc; - lvcc = kzalloc_obj(*lvcc); - if (likely(lvcc != NULL)) { - skb_queue_head_init(&lvcc->tx.backlog); -#ifdef DEBUG - lvcc->vci = -1; -#endif - } - return lvcc; -} - -static int lanai_get_sized_buffer(struct lanai_dev *lanai, - struct lanai_buffer *buf, int max_sdu, int multiplier, - const char *name) -{ - int size; - if (unlikely(max_sdu < 1)) - max_sdu = 1; - max_sdu = aal5_size(max_sdu); - size = (max_sdu + 16) * multiplier + 16; - lanai_buf_allocate(buf, size, max_sdu + 32, lanai->pci); - if (unlikely(buf->start == NULL)) - return -ENOMEM; - if (unlikely(lanai_buf_size(buf) < size)) - printk(KERN_WARNING DEV_LABEL "(itf %d): wanted %d bytes " - "for %s buffer, got only %zu\n", lanai->number, size, - name, lanai_buf_size(buf)); - DPRINTK("Allocated %zu byte %s buffer\n", lanai_buf_size(buf), name); - return 0; -} - -/* Setup a RX buffer for a currently unbound AAL5 vci */ -static inline int lanai_setup_rx_vci_aal5(struct lanai_dev *lanai, - struct lanai_vcc *lvcc, const struct atm_qos *qos) -{ - return lanai_get_sized_buffer(lanai, &lvcc->rx.buf, - qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, "RX"); -} - -/* Setup a TX buffer for a currently unbound AAL5 vci */ -static int lanai_setup_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc, - const struct atm_qos *qos) -{ - int max_sdu, multiplier; - if (qos->aal == ATM_AAL0) { - lvcc->tx.unqueue = vcc_tx_unqueue_aal0; - max_sdu = ATM_CELL_SIZE - 1; - multiplier = AAL0_TX_MULTIPLIER; - } else { - lvcc->tx.unqueue = vcc_tx_unqueue_aal5; - max_sdu = qos->txtp.max_sdu; - multiplier = AAL5_TX_MULTIPLIER; - } - return lanai_get_sized_buffer(lanai, &lvcc->tx.buf, max_sdu, - multiplier, "TX"); -} - -static inline void host_vcc_bind(struct lanai_dev *lanai, - struct lanai_vcc *lvcc, vci_t vci) -{ - if (lvcc->vbase != NULL) - return; /* We already were bound in the other direction */ - DPRINTK("Binding vci %d\n", vci); -#ifdef USE_POWERDOWN - if (lanai->nbound++ == 0) { - DPRINTK("Coming out of powerdown\n"); - lanai->conf1 &= ~CONFIG1_POWERDOWN; - conf1_write(lanai); - conf2_write(lanai); - } -#endif - lvcc->vbase = cardvcc_addr(lanai, vci); - lanai->vccs[lvcc->vci = vci] = lvcc; -} - -static inline void host_vcc_unbind(struct lanai_dev *lanai, - struct lanai_vcc *lvcc) -{ - if (lvcc->vbase == NULL) - return; /* This vcc was never bound */ - DPRINTK("Unbinding vci %d\n", lvcc->vci); - lvcc->vbase = NULL; - lanai->vccs[lvcc->vci] = NULL; -#ifdef USE_POWERDOWN - if (--lanai->nbound == 0) { - DPRINTK("Going into powerdown\n"); - lanai->conf1 |= CONFIG1_POWERDOWN; - conf1_write(lanai); - } -#endif -} - -/* -------------------- RESET CARD: */ - -static void lanai_reset(struct lanai_dev *lanai) -{ - printk(KERN_CRIT DEV_LABEL "(itf %d): *NOT* resetting - not " - "implemented\n", lanai->number); - /* TODO */ - /* The following is just a hack until we write the real - * resetter - at least ack whatever interrupt sent us - * here - */ - reg_write(lanai, INT_ALL, IntAck_Reg); - lanai->stats.card_reset++; -} - -/* -------------------- SERVICE LIST UTILITIES: */ - -/* - * Allocate service buffer and tell card about it - */ -static int service_buffer_allocate(struct lanai_dev *lanai) -{ - lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 8, - lanai->pci); - if (unlikely(lanai->service.start == NULL)) - return -ENOMEM; - DPRINTK("allocated service buffer at %p, size %zu(%d)\n", - lanai->service.start, - lanai_buf_size(&lanai->service), - lanai_buf_size_cardorder(&lanai->service)); - /* Clear ServWrite register to be safe */ - reg_write(lanai, 0, ServWrite_Reg); - /* ServiceStuff register contains size and address of buffer */ - reg_write(lanai, - SSTUFF_SET_SIZE(lanai_buf_size_cardorder(&lanai->service)) | - SSTUFF_SET_ADDR(lanai->service.dmaaddr), - ServiceStuff_Reg); - return 0; -} - -static inline void service_buffer_deallocate(struct lanai_dev *lanai) -{ - lanai_buf_deallocate(&lanai->service, lanai->pci); -} - -/* Bitfields in service list */ -#define SERVICE_TX (0x80000000) /* Was from transmission */ -#define SERVICE_TRASH (0x40000000) /* RXed PDU was trashed */ -#define SERVICE_CRCERR (0x20000000) /* RXed PDU had CRC error */ -#define SERVICE_CI (0x10000000) /* RXed PDU had CI set */ -#define SERVICE_CLP (0x08000000) /* RXed PDU had CLP set */ -#define SERVICE_STREAM (0x04000000) /* RX Stream mode */ -#define SERVICE_GET_VCI(x) (((x)>>16)&0x3FF) -#define SERVICE_GET_END(x) ((x)&0x1FFF) - -/* Handle one thing from the service list - returns true if it marked a - * VCC ready for xmit - */ -static int handle_service(struct lanai_dev *lanai, u32 s) -{ - vci_t vci = SERVICE_GET_VCI(s); - struct lanai_vcc *lvcc; - read_lock(&vcc_sklist_lock); - lvcc = lanai->vccs[vci]; - if (unlikely(lvcc == NULL)) { - read_unlock(&vcc_sklist_lock); - DPRINTK("(itf %d) got service entry 0x%X for nonexistent " - "vcc %d\n", lanai->number, (unsigned int) s, vci); - if (s & SERVICE_TX) - lanai->stats.service_notx++; - else - lanai->stats.service_norx++; - return 0; - } - if (s & SERVICE_TX) { /* segmentation interrupt */ - if (unlikely(lvcc->tx.atmvcc == NULL)) { - read_unlock(&vcc_sklist_lock); - DPRINTK("(itf %d) got service entry 0x%X for non-TX " - "vcc %d\n", lanai->number, (unsigned int) s, vci); - lanai->stats.service_notx++; - return 0; - } - __set_bit(vci, lanai->transmit_ready); - lvcc->tx.endptr = SERVICE_GET_END(s); - read_unlock(&vcc_sklist_lock); - return 1; - } - if (unlikely(lvcc->rx.atmvcc == NULL)) { - read_unlock(&vcc_sklist_lock); - DPRINTK("(itf %d) got service entry 0x%X for non-RX " - "vcc %d\n", lanai->number, (unsigned int) s, vci); - lanai->stats.service_norx++; - return 0; - } - if (unlikely(lvcc->rx.atmvcc->qos.aal != ATM_AAL5)) { - read_unlock(&vcc_sklist_lock); - DPRINTK("(itf %d) got RX service entry 0x%X for non-AAL5 " - "vcc %d\n", lanai->number, (unsigned int) s, vci); - lanai->stats.service_rxnotaal5++; - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); - return 0; - } - if (likely(!(s & (SERVICE_TRASH | SERVICE_STREAM | SERVICE_CRCERR)))) { - vcc_rx_aal5(lvcc, SERVICE_GET_END(s)); - read_unlock(&vcc_sklist_lock); - return 0; - } - if (s & SERVICE_TRASH) { - int bytes; - read_unlock(&vcc_sklist_lock); - DPRINTK("got trashed rx pdu on vci %d\n", vci); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); - lvcc->stats.x.aal5.service_trash++; - bytes = (SERVICE_GET_END(s) * 16) - - (((unsigned long) lvcc->rx.buf.ptr) - - ((unsigned long) lvcc->rx.buf.start)) + 47; - if (bytes < 0) - bytes += lanai_buf_size(&lvcc->rx.buf); - lanai->stats.ovfl_trash += (bytes / 48); - return 0; - } - if (s & SERVICE_STREAM) { - read_unlock(&vcc_sklist_lock); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); - lvcc->stats.x.aal5.service_stream++; - printk(KERN_ERR DEV_LABEL "(itf %d): Got AAL5 stream " - "PDU on VCI %d!\n", lanai->number, vci); - lanai_reset(lanai); - return 0; - } - DPRINTK("got rx crc error on vci %d\n", vci); - atomic_inc(&lvcc->rx.atmvcc->stats->rx_err); - lvcc->stats.x.aal5.service_rxcrc++; - lvcc->rx.buf.ptr = &lvcc->rx.buf.start[SERVICE_GET_END(s) * 4]; - cardvcc_write(lvcc, SERVICE_GET_END(s), vcc_rxreadptr); - read_unlock(&vcc_sklist_lock); - return 0; -} - -/* Try transmitting on all VCIs that we marked ready to serve */ -static void iter_transmit(struct lanai_dev *lanai, vci_t vci) -{ - struct lanai_vcc *lvcc = lanai->vccs[vci]; - if (vcc_is_backlogged(lvcc)) - lvcc->tx.unqueue(lanai, lvcc, lvcc->tx.endptr); -} - -/* Run service queue -- called from interrupt context or with - * interrupts otherwise disabled and with the lanai->servicelock - * lock held - */ -static void run_service(struct lanai_dev *lanai) -{ - int ntx = 0; - u32 wreg = reg_read(lanai, ServWrite_Reg); - const u32 *end = lanai->service.start + wreg; - while (lanai->service.ptr != end) { - ntx += handle_service(lanai, - le32_to_cpup(lanai->service.ptr++)); - if (lanai->service.ptr >= lanai->service.end) - lanai->service.ptr = lanai->service.start; - } - reg_write(lanai, wreg, ServRead_Reg); - if (ntx != 0) { - read_lock(&vcc_sklist_lock); - vci_bitfield_iterate(lanai, lanai->transmit_ready, - iter_transmit); - bitmap_zero(lanai->transmit_ready, NUM_VCI); - read_unlock(&vcc_sklist_lock); - } -} - -/* -------------------- GATHER STATISTICS: */ - -static void get_statistics(struct lanai_dev *lanai) -{ - u32 statreg = reg_read(lanai, Statistics_Reg); - lanai->stats.atm_ovfl += STATS_GET_FIFO_OVFL(statreg); - lanai->stats.hec_err += STATS_GET_HEC_ERR(statreg); - lanai->stats.vci_trash += STATS_GET_BAD_VCI(statreg); - lanai->stats.ovfl_trash += STATS_GET_BUF_OVFL(statreg); -} - -/* -------------------- POLLING TIMER: */ - -#ifndef DEBUG_RW -/* Try to undequeue 1 backlogged vcc */ -static void iter_dequeue(struct lanai_dev *lanai, vci_t vci) -{ - struct lanai_vcc *lvcc = lanai->vccs[vci]; - int endptr; - if (lvcc == NULL || lvcc->tx.atmvcc == NULL || - !vcc_is_backlogged(lvcc)) { - __clear_bit(vci, lanai->backlog_vccs); - return; - } - endptr = TXREADPTR_GET_PTR(cardvcc_read(lvcc, vcc_txreadptr)); - lvcc->tx.unqueue(lanai, lvcc, endptr); -} -#endif /* !DEBUG_RW */ - -static void lanai_timed_poll(struct timer_list *t) -{ - struct lanai_dev *lanai = timer_container_of(lanai, t, timer); -#ifndef DEBUG_RW - unsigned long flags; -#ifdef USE_POWERDOWN - if (lanai->conf1 & CONFIG1_POWERDOWN) - return; -#endif /* USE_POWERDOWN */ - local_irq_save(flags); - /* If we can grab the spinlock, check if any services need to be run */ - if (spin_trylock(&lanai->servicelock)) { - run_service(lanai); - spin_unlock(&lanai->servicelock); - } - /* ...and see if any backlogged VCs can make progress */ - /* unfortunately linux has no read_trylock() currently */ - read_lock(&vcc_sklist_lock); - vci_bitfield_iterate(lanai, lanai->backlog_vccs, iter_dequeue); - read_unlock(&vcc_sklist_lock); - local_irq_restore(flags); - - get_statistics(lanai); -#endif /* !DEBUG_RW */ - mod_timer(&lanai->timer, jiffies + LANAI_POLL_PERIOD); -} - -static inline void lanai_timed_poll_start(struct lanai_dev *lanai) -{ - timer_setup(&lanai->timer, lanai_timed_poll, 0); - lanai->timer.expires = jiffies + LANAI_POLL_PERIOD; - add_timer(&lanai->timer); -} - -static inline void lanai_timed_poll_stop(struct lanai_dev *lanai) -{ - timer_delete_sync(&lanai->timer); -} - -/* -------------------- INTERRUPT SERVICE: */ - -static inline void lanai_int_1(struct lanai_dev *lanai, u32 reason) -{ - u32 ack = 0; - if (reason & INT_SERVICE) { - ack = INT_SERVICE; - spin_lock(&lanai->servicelock); - run_service(lanai); - spin_unlock(&lanai->servicelock); - } - if (reason & (INT_AAL0_STR | INT_AAL0)) { - ack |= reason & (INT_AAL0_STR | INT_AAL0); - vcc_rx_aal0(lanai); - } - /* The rest of the interrupts are pretty rare */ - if (ack == reason) - goto done; - if (reason & INT_STATS) { - reason &= ~INT_STATS; /* No need to ack */ - get_statistics(lanai); - } - if (reason & INT_STATUS) { - ack |= reason & INT_STATUS; - lanai_check_status(lanai); - } - if (unlikely(reason & INT_DMASHUT)) { - printk(KERN_ERR DEV_LABEL "(itf %d): driver error - DMA " - "shutdown, reason=0x%08X, address=0x%08X\n", - lanai->number, (unsigned int) (reason & INT_DMASHUT), - (unsigned int) reg_read(lanai, DMA_Addr_Reg)); - if (reason & INT_TABORTBM) { - lanai_reset(lanai); - return; - } - ack |= (reason & INT_DMASHUT); - printk(KERN_ERR DEV_LABEL "(itf %d): re-enabling DMA\n", - lanai->number); - conf1_write(lanai); - lanai->stats.dma_reenable++; - pcistatus_check(lanai, 0); - } - if (unlikely(reason & INT_TABORTSENT)) { - ack |= (reason & INT_TABORTSENT); - printk(KERN_ERR DEV_LABEL "(itf %d): sent PCI target abort\n", - lanai->number); - pcistatus_check(lanai, 0); - } - if (unlikely(reason & INT_SEGSHUT)) { - printk(KERN_ERR DEV_LABEL "(itf %d): driver error - " - "segmentation shutdown, reason=0x%08X\n", lanai->number, - (unsigned int) (reason & INT_SEGSHUT)); - lanai_reset(lanai); - return; - } - if (unlikely(reason & (INT_PING | INT_WAKE))) { - printk(KERN_ERR DEV_LABEL "(itf %d): driver error - " - "unexpected interrupt 0x%08X, resetting\n", - lanai->number, - (unsigned int) (reason & (INT_PING | INT_WAKE))); - lanai_reset(lanai); - return; - } -#ifdef DEBUG - if (unlikely(ack != reason)) { - DPRINTK("unacked ints: 0x%08X\n", - (unsigned int) (reason & ~ack)); - ack = reason; - } -#endif - done: - if (ack != 0) - reg_write(lanai, ack, IntAck_Reg); -} - -static irqreturn_t lanai_int(int irq, void *devid) -{ - struct lanai_dev *lanai = devid; - u32 reason; - -#ifdef USE_POWERDOWN - /* - * If we're powered down we shouldn't be generating any interrupts - - * so assume that this is a shared interrupt line and it's for someone - * else - */ - if (unlikely(lanai->conf1 & CONFIG1_POWERDOWN)) - return IRQ_NONE; -#endif - - reason = intr_pending(lanai); - if (reason == 0) - return IRQ_NONE; /* Must be for someone else */ - - do { - if (unlikely(reason == 0xFFFFFFFF)) - break; /* Maybe we've been unplugged? */ - lanai_int_1(lanai, reason); - reason = intr_pending(lanai); - } while (reason != 0); - - return IRQ_HANDLED; -} - -/* TODO - it would be nice if we could use the "delayed interrupt" system - * to some advantage - */ - -/* -------------------- CHECK BOARD ID/REV: */ - -/* - * The board id and revision are stored both in the reset register and - * in the PCI configuration space - the documentation says to check - * each of them. If revp!=NULL we store the revision there - */ -static int check_board_id_and_rev(const char *name, u32 val, int *revp) -{ - DPRINTK("%s says board_id=%d, board_rev=%d\n", name, - (int) RESET_GET_BOARD_ID(val), - (int) RESET_GET_BOARD_REV(val)); - if (RESET_GET_BOARD_ID(val) != BOARD_ID_LANAI256) { - printk(KERN_ERR DEV_LABEL ": Found %s board-id %d -- not a " - "Lanai 25.6\n", name, (int) RESET_GET_BOARD_ID(val)); - return -ENODEV; - } - if (revp != NULL) - *revp = RESET_GET_BOARD_REV(val); - return 0; -} - -/* -------------------- PCI INITIALIZATION/SHUTDOWN: */ - -static int lanai_pci_start(struct lanai_dev *lanai) -{ - struct pci_dev *pci = lanai->pci; - int result; - - if (pci_enable_device(pci) != 0) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't enable " - "PCI device", lanai->number); - return -ENXIO; - } - pci_set_master(pci); - if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING DEV_LABEL - "(itf %d): No suitable DMA available.\n", lanai->number); - return -EBUSY; - } - result = check_board_id_and_rev("PCI", pci->subsystem_device, NULL); - if (result != 0) - return result; - /* Set latency timer to zero as per lanai docs */ - result = pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0); - if (result != PCIBIOS_SUCCESSFUL) { - printk(KERN_ERR DEV_LABEL "(itf %d): can't write " - "PCI_LATENCY_TIMER: %d\n", lanai->number, result); - return -EINVAL; - } - pcistatus_check(lanai, 1); - pcistatus_check(lanai, 0); - return 0; -} - -/* -------------------- VPI/VCI ALLOCATION: */ - -/* - * We _can_ use VCI==0 for normal traffic, but only for UBR (or we'll - * get a CBRZERO interrupt), and we can use it only if no one is receiving - * AAL0 traffic (since they will use the same queue) - according to the - * docs we shouldn't even use it for AAL0 traffic - */ -static inline int vci0_is_ok(struct lanai_dev *lanai, - const struct atm_qos *qos) -{ - if (qos->txtp.traffic_class == ATM_CBR || qos->aal == ATM_AAL0) - return 0; - if (qos->rxtp.traffic_class != ATM_NONE) { - if (lanai->naal0 != 0) - return 0; - lanai->conf2 |= CONFIG2_VCI0_NORMAL; - conf2_write_if_powerup(lanai); - } - return 1; -} - -/* return true if vci is currently unused, or if requested qos is - * compatible - */ -static int vci_is_ok(struct lanai_dev *lanai, vci_t vci, - const struct atm_vcc *atmvcc) -{ - const struct atm_qos *qos = &atmvcc->qos; - const struct lanai_vcc *lvcc = lanai->vccs[vci]; - if (vci == 0 && !vci0_is_ok(lanai, qos)) - return 0; - if (unlikely(lvcc != NULL)) { - if (qos->rxtp.traffic_class != ATM_NONE && - lvcc->rx.atmvcc != NULL && lvcc->rx.atmvcc != atmvcc) - return 0; - if (qos->txtp.traffic_class != ATM_NONE && - lvcc->tx.atmvcc != NULL && lvcc->tx.atmvcc != atmvcc) - return 0; - if (qos->txtp.traffic_class == ATM_CBR && - lanai->cbrvcc != NULL && lanai->cbrvcc != atmvcc) - return 0; - } - if (qos->aal == ATM_AAL0 && lanai->naal0 == 0 && - qos->rxtp.traffic_class != ATM_NONE) { - const struct lanai_vcc *vci0 = lanai->vccs[0]; - if (vci0 != NULL && vci0->rx.atmvcc != NULL) - return 0; - lanai->conf2 &= ~CONFIG2_VCI0_NORMAL; - conf2_write_if_powerup(lanai); - } - return 1; -} - -static int lanai_normalize_ci(struct lanai_dev *lanai, - const struct atm_vcc *atmvcc, short *vpip, vci_t *vcip) -{ - switch (*vpip) { - case ATM_VPI_ANY: - *vpip = 0; - fallthrough; - case 0: - break; - default: - return -EADDRINUSE; - } - switch (*vcip) { - case ATM_VCI_ANY: - for (*vcip = ATM_NOT_RSV_VCI; *vcip < lanai->num_vci; - (*vcip)++) - if (vci_is_ok(lanai, *vcip, atmvcc)) - return 0; - return -EADDRINUSE; - default: - if (*vcip >= lanai->num_vci || *vcip < 0 || - !vci_is_ok(lanai, *vcip, atmvcc)) - return -EADDRINUSE; - } - return 0; -} - -/* -------------------- MANAGE CBR: */ - -/* - * CBR ICG is stored as a fixed-point number with 4 fractional bits. - * Note that storing a number greater than 2046.0 will result in - * incorrect shaping - */ -#define CBRICG_FRAC_BITS (4) -#define CBRICG_MAX (2046 << CBRICG_FRAC_BITS) - -/* - * ICG is related to PCR with the formula PCR = MAXPCR / (ICG + 1) - * where MAXPCR is (according to the docs) 25600000/(54*8), - * which is equal to (3125<<9)/27. - * - * Solving for ICG, we get: - * ICG = MAXPCR/PCR - 1 - * ICG = (3125<<9)/(27*PCR) - 1 - * ICG = ((3125<<9) - (27*PCR)) / (27*PCR) - * - * The end result is supposed to be a fixed-point number with FRAC_BITS - * bits of a fractional part, so we keep everything in the numerator - * shifted by that much as we compute - * - */ -static int pcr_to_cbricg(const struct atm_qos *qos) -{ - int rounddown = 0; /* 1 = Round PCR down, i.e. round ICG _up_ */ - int x, icg, pcr = atm_pcr_goal(&qos->txtp); - if (pcr == 0) /* Use maximum bandwidth */ - return 0; - if (pcr < 0) { - rounddown = 1; - pcr = -pcr; - } - x = pcr * 27; - icg = (3125 << (9 + CBRICG_FRAC_BITS)) - (x << CBRICG_FRAC_BITS); - if (rounddown) - icg += x - 1; - icg /= x; - if (icg > CBRICG_MAX) - icg = CBRICG_MAX; - DPRINTK("pcr_to_cbricg: pcr=%d rounddown=%c icg=%d\n", - pcr, rounddown ? 'Y' : 'N', icg); - return icg; -} - -static inline void lanai_cbr_setup(struct lanai_dev *lanai) -{ - reg_write(lanai, pcr_to_cbricg(&lanai->cbrvcc->qos), CBR_ICG_Reg); - reg_write(lanai, lanai->cbrvcc->vci, CBR_PTR_Reg); - lanai->conf2 |= CONFIG2_CBR_ENABLE; - conf2_write(lanai); -} - -static inline void lanai_cbr_shutdown(struct lanai_dev *lanai) -{ - lanai->conf2 &= ~CONFIG2_CBR_ENABLE; - conf2_write(lanai); -} - -/* -------------------- OPERATIONS: */ - -/* setup a newly detected device */ -static int lanai_dev_open(struct atm_dev *atmdev) -{ - struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; - unsigned long raw_base; - int result; - - DPRINTK("In lanai_dev_open()\n"); - /* Basic device fields */ - lanai->number = atmdev->number; - lanai->num_vci = NUM_VCI; - bitmap_zero(lanai->backlog_vccs, NUM_VCI); - bitmap_zero(lanai->transmit_ready, NUM_VCI); - lanai->naal0 = 0; -#ifdef USE_POWERDOWN - lanai->nbound = 0; -#endif - lanai->cbrvcc = NULL; - memset(&lanai->stats, 0, sizeof lanai->stats); - spin_lock_init(&lanai->endtxlock); - spin_lock_init(&lanai->servicelock); - atmdev->ci_range.vpi_bits = 0; - atmdev->ci_range.vci_bits = 0; - while (1 << atmdev->ci_range.vci_bits < lanai->num_vci) - atmdev->ci_range.vci_bits++; - atmdev->link_rate = ATM_25_PCR; - - /* 3.2: PCI initialization */ - if ((result = lanai_pci_start(lanai)) != 0) - goto error; - raw_base = lanai->pci->resource[0].start; - lanai->base = (bus_addr_t) ioremap(raw_base, LANAI_MAPPING_SIZE); - if (lanai->base == NULL) { - printk(KERN_ERR DEV_LABEL ": couldn't remap I/O space\n"); - result = -ENOMEM; - goto error_pci; - } - /* 3.3: Reset lanai and PHY */ - reset_board(lanai); - lanai->conf1 = reg_read(lanai, Config1_Reg); - lanai->conf1 &= ~(CONFIG1_GPOUT1 | CONFIG1_POWERDOWN | - CONFIG1_MASK_LEDMODE); - lanai->conf1 |= CONFIG1_SET_LEDMODE(LEDMODE_NOT_SOOL); - reg_write(lanai, lanai->conf1 | CONFIG1_GPOUT1, Config1_Reg); - udelay(1000); - conf1_write(lanai); - - /* - * 3.4: Turn on endian mode for big-endian hardware - * We don't actually want to do this - the actual bit fields - * in the endian register are not documented anywhere. - * Instead we do the bit-flipping ourselves on big-endian - * hardware. - * - * 3.5: get the board ID/rev by reading the reset register - */ - result = check_board_id_and_rev("register", - reg_read(lanai, Reset_Reg), &lanai->board_rev); - if (result != 0) - goto error_unmap; - - /* 3.6: read EEPROM */ - if ((result = eeprom_read(lanai)) != 0) - goto error_unmap; - if ((result = eeprom_validate(lanai)) != 0) - goto error_unmap; - - /* 3.7: re-reset PHY, do loopback tests, setup PHY */ - reg_write(lanai, lanai->conf1 | CONFIG1_GPOUT1, Config1_Reg); - udelay(1000); - conf1_write(lanai); - /* TODO - loopback tests */ - lanai->conf1 |= (CONFIG1_GPOUT2 | CONFIG1_GPOUT3 | CONFIG1_DMA_ENABLE); - conf1_write(lanai); - - /* 3.8/3.9: test and initialize card SRAM */ - if ((result = sram_test_and_clear(lanai)) != 0) - goto error_unmap; - - /* 3.10: initialize lanai registers */ - lanai->conf1 |= CONFIG1_DMA_ENABLE; - conf1_write(lanai); - if ((result = service_buffer_allocate(lanai)) != 0) - goto error_unmap; - if ((result = vcc_table_allocate(lanai)) != 0) - goto error_service; - lanai->conf2 = (lanai->num_vci >= 512 ? CONFIG2_HOWMANY : 0) | - CONFIG2_HEC_DROP | /* ??? */ CONFIG2_PTI7_MODE; - conf2_write(lanai); - reg_write(lanai, TX_FIFO_DEPTH, TxDepth_Reg); - reg_write(lanai, 0, CBR_ICG_Reg); /* CBR defaults to no limit */ - if ((result = request_irq(lanai->pci->irq, lanai_int, IRQF_SHARED, - DEV_LABEL, lanai)) != 0) { - printk(KERN_ERR DEV_LABEL ": can't allocate interrupt\n"); - goto error_vcctable; - } - mb(); /* Make sure that all that made it */ - intr_enable(lanai, INT_ALL & ~(INT_PING | INT_WAKE)); - /* 3.11: initialize loop mode (i.e. turn looping off) */ - lanai->conf1 = (lanai->conf1 & ~CONFIG1_MASK_LOOPMODE) | - CONFIG1_SET_LOOPMODE(LOOPMODE_NORMAL) | - CONFIG1_GPOUT2 | CONFIG1_GPOUT3; - conf1_write(lanai); - lanai->status = reg_read(lanai, Status_Reg); - /* We're now done initializing this card */ -#ifdef USE_POWERDOWN - lanai->conf1 |= CONFIG1_POWERDOWN; - conf1_write(lanai); -#endif - memcpy(atmdev->esi, eeprom_mac(lanai), ESI_LEN); - lanai_timed_poll_start(lanai); - printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=%p, irq=%u " - "(%pMF)\n", lanai->number, (int) lanai->pci->revision, - lanai->base, lanai->pci->irq, atmdev->esi); - printk(KERN_NOTICE DEV_LABEL "(itf %d): LANAI%s, serialno=%u(0x%X), " - "board_rev=%d\n", lanai->number, - lanai->type==lanai2 ? "2" : "HB", (unsigned int) lanai->serialno, - (unsigned int) lanai->serialno, lanai->board_rev); - return 0; - - error_vcctable: - vcc_table_deallocate(lanai); - error_service: - service_buffer_deallocate(lanai); - error_unmap: - reset_board(lanai); -#ifdef USE_POWERDOWN - lanai->conf1 = reg_read(lanai, Config1_Reg) | CONFIG1_POWERDOWN; - conf1_write(lanai); -#endif - iounmap(lanai->base); - lanai->base = NULL; - error_pci: - pci_disable_device(lanai->pci); - error: - return result; -} - -/* called when device is being shutdown, and all vcc's are gone - higher - * levels will deallocate the atm device for us - */ -static void lanai_dev_close(struct atm_dev *atmdev) -{ - struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; - if (lanai->base==NULL) - return; - printk(KERN_INFO DEV_LABEL "(itf %d): shutting down interface\n", - lanai->number); - lanai_timed_poll_stop(lanai); -#ifdef USE_POWERDOWN - lanai->conf1 = reg_read(lanai, Config1_Reg) & ~CONFIG1_POWERDOWN; - conf1_write(lanai); -#endif - intr_disable(lanai, INT_ALL); - free_irq(lanai->pci->irq, lanai); - reset_board(lanai); -#ifdef USE_POWERDOWN - lanai->conf1 |= CONFIG1_POWERDOWN; - conf1_write(lanai); -#endif - pci_disable_device(lanai->pci); - vcc_table_deallocate(lanai); - service_buffer_deallocate(lanai); - iounmap(lanai->base); - kfree(lanai); -} - -/* close a vcc */ -static void lanai_close(struct atm_vcc *atmvcc) -{ - struct lanai_vcc *lvcc = (struct lanai_vcc *) atmvcc->dev_data; - struct lanai_dev *lanai = (struct lanai_dev *) atmvcc->dev->dev_data; - if (lvcc == NULL) - return; - clear_bit(ATM_VF_READY, &atmvcc->flags); - clear_bit(ATM_VF_PARTIAL, &atmvcc->flags); - if (lvcc->rx.atmvcc == atmvcc) { - lanai_shutdown_rx_vci(lvcc); - if (atmvcc->qos.aal == ATM_AAL0) { - if (--lanai->naal0 <= 0) - aal0_buffer_free(lanai); - } else - lanai_buf_deallocate(&lvcc->rx.buf, lanai->pci); - lvcc->rx.atmvcc = NULL; - } - if (lvcc->tx.atmvcc == atmvcc) { - if (atmvcc == lanai->cbrvcc) { - if (lvcc->vbase != NULL) - lanai_cbr_shutdown(lanai); - lanai->cbrvcc = NULL; - } - lanai_shutdown_tx_vci(lanai, lvcc); - lanai_buf_deallocate(&lvcc->tx.buf, lanai->pci); - lvcc->tx.atmvcc = NULL; - } - if (--lvcc->nref == 0) { - host_vcc_unbind(lanai, lvcc); - kfree(lvcc); - } - atmvcc->dev_data = NULL; - clear_bit(ATM_VF_ADDR, &atmvcc->flags); -} - -/* open a vcc on the card to vpi/vci */ -static int lanai_open(struct atm_vcc *atmvcc) -{ - struct lanai_dev *lanai; - struct lanai_vcc *lvcc; - int result = 0; - int vci = atmvcc->vci; - short vpi = atmvcc->vpi; - /* we don't support partial open - it's not really useful anyway */ - if ((test_bit(ATM_VF_PARTIAL, &atmvcc->flags)) || - (vpi == ATM_VPI_UNSPEC) || (vci == ATM_VCI_UNSPEC)) - return -EINVAL; - lanai = (struct lanai_dev *) atmvcc->dev->dev_data; - result = lanai_normalize_ci(lanai, atmvcc, &vpi, &vci); - if (unlikely(result != 0)) - goto out; - set_bit(ATM_VF_ADDR, &atmvcc->flags); - if (atmvcc->qos.aal != ATM_AAL0 && atmvcc->qos.aal != ATM_AAL5) - return -EINVAL; - DPRINTK(DEV_LABEL "(itf %d): open %d.%d\n", lanai->number, - (int) vpi, vci); - lvcc = lanai->vccs[vci]; - if (lvcc == NULL) { - lvcc = new_lanai_vcc(); - if (unlikely(lvcc == NULL)) - return -ENOMEM; - atmvcc->dev_data = lvcc; - } - lvcc->nref++; - if (atmvcc->qos.rxtp.traffic_class != ATM_NONE) { - APRINTK(lvcc->rx.atmvcc == NULL, "rx.atmvcc!=NULL, vci=%d\n", - vci); - if (atmvcc->qos.aal == ATM_AAL0) { - if (lanai->naal0 == 0) - result = aal0_buffer_allocate(lanai); - } else - result = lanai_setup_rx_vci_aal5( - lanai, lvcc, &atmvcc->qos); - if (unlikely(result != 0)) - goto out_free; - lvcc->rx.atmvcc = atmvcc; - lvcc->stats.rx_nomem = 0; - lvcc->stats.x.aal5.rx_badlen = 0; - lvcc->stats.x.aal5.service_trash = 0; - lvcc->stats.x.aal5.service_stream = 0; - lvcc->stats.x.aal5.service_rxcrc = 0; - if (atmvcc->qos.aal == ATM_AAL0) - lanai->naal0++; - } - if (atmvcc->qos.txtp.traffic_class != ATM_NONE) { - APRINTK(lvcc->tx.atmvcc == NULL, "tx.atmvcc!=NULL, vci=%d\n", - vci); - result = lanai_setup_tx_vci(lanai, lvcc, &atmvcc->qos); - if (unlikely(result != 0)) - goto out_free; - lvcc->tx.atmvcc = atmvcc; - if (atmvcc->qos.txtp.traffic_class == ATM_CBR) { - APRINTK(lanai->cbrvcc == NULL, - "cbrvcc!=NULL, vci=%d\n", vci); - lanai->cbrvcc = atmvcc; - } - } - host_vcc_bind(lanai, lvcc, vci); - /* - * Make sure everything made it to RAM before we tell the card about - * the VCC - */ - wmb(); - if (atmvcc == lvcc->rx.atmvcc) - host_vcc_start_rx(lvcc); - if (atmvcc == lvcc->tx.atmvcc) { - host_vcc_start_tx(lvcc); - if (lanai->cbrvcc == atmvcc) - lanai_cbr_setup(lanai); - } - set_bit(ATM_VF_READY, &atmvcc->flags); - return 0; - out_free: - lanai_close(atmvcc); - out: - return result; -} - -static int lanai_send(struct atm_vcc *atmvcc, struct sk_buff *skb) -{ - struct lanai_vcc *lvcc = (struct lanai_vcc *) atmvcc->dev_data; - struct lanai_dev *lanai = (struct lanai_dev *) atmvcc->dev->dev_data; - unsigned long flags; - if (unlikely(lvcc == NULL || lvcc->vbase == NULL || - lvcc->tx.atmvcc != atmvcc)) - goto einval; -#ifdef DEBUG - if (unlikely(skb == NULL)) { - DPRINTK("lanai_send: skb==NULL for vci=%d\n", atmvcc->vci); - goto einval; - } - if (unlikely(lanai == NULL)) { - DPRINTK("lanai_send: lanai==NULL for vci=%d\n", atmvcc->vci); - goto einval; - } -#endif - ATM_SKB(skb)->vcc = atmvcc; - switch (atmvcc->qos.aal) { - case ATM_AAL5: - read_lock_irqsave(&vcc_sklist_lock, flags); - vcc_tx_aal5(lanai, lvcc, skb); - read_unlock_irqrestore(&vcc_sklist_lock, flags); - return 0; - case ATM_AAL0: - if (unlikely(skb->len != ATM_CELL_SIZE-1)) - goto einval; - /* NOTE - this next line is technically invalid - we haven't unshared skb */ - cpu_to_be32s((u32 *) skb->data); - read_lock_irqsave(&vcc_sklist_lock, flags); - vcc_tx_aal0(lanai, lvcc, skb); - read_unlock_irqrestore(&vcc_sklist_lock, flags); - return 0; - } - DPRINTK("lanai_send: bad aal=%d on vci=%d\n", (int) atmvcc->qos.aal, - atmvcc->vci); - einval: - lanai_free_skb(atmvcc, skb); - return -EINVAL; -} - -static int lanai_change_qos(struct atm_vcc *atmvcc, - /*const*/ struct atm_qos *qos, int flags) -{ - return -EBUSY; /* TODO: need to write this */ -} - -#ifndef CONFIG_PROC_FS -#define lanai_proc_read NULL -#else -static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page) -{ - struct lanai_dev *lanai = (struct lanai_dev *) atmdev->dev_data; - loff_t left = *pos; - struct lanai_vcc *lvcc; - if (left-- == 0) - return sprintf(page, DEV_LABEL "(itf %d): chip=LANAI%s, " - "serial=%u, magic=0x%08X, num_vci=%d\n", - atmdev->number, lanai->type==lanai2 ? "2" : "HB", - (unsigned int) lanai->serialno, - (unsigned int) lanai->magicno, lanai->num_vci); - if (left-- == 0) - return sprintf(page, "revision: board=%d, pci_if=%d\n", - lanai->board_rev, (int) lanai->pci->revision); - if (left-- == 0) - return sprintf(page, "EEPROM ESI: %pM\n", - &lanai->eeprom[EEPROM_MAC]); - if (left-- == 0) - return sprintf(page, "status: SOOL=%d, LOCD=%d, LED=%d, " - "GPIN=%d\n", (lanai->status & STATUS_SOOL) ? 1 : 0, - (lanai->status & STATUS_LOCD) ? 1 : 0, - (lanai->status & STATUS_LED) ? 1 : 0, - (lanai->status & STATUS_GPIN) ? 1 : 0); - if (left-- == 0) - return sprintf(page, "global buffer sizes: service=%zu, " - "aal0_rx=%zu\n", lanai_buf_size(&lanai->service), - lanai->naal0 ? lanai_buf_size(&lanai->aal0buf) : 0); - if (left-- == 0) { - get_statistics(lanai); - return sprintf(page, "cells in error: overflow=%u, " - "closed_vci=%u, bad_HEC=%u, rx_fifo=%u\n", - lanai->stats.ovfl_trash, lanai->stats.vci_trash, - lanai->stats.hec_err, lanai->stats.atm_ovfl); - } - if (left-- == 0) - return sprintf(page, "PCI errors: parity_detect=%u, " - "master_abort=%u, master_target_abort=%u,\n", - lanai->stats.pcierr_parity_detect, - lanai->stats.pcierr_serr_set, - lanai->stats.pcierr_m_target_abort); - if (left-- == 0) - return sprintf(page, " slave_target_abort=%u, " - "master_parity=%u\n", lanai->stats.pcierr_s_target_abort, - lanai->stats.pcierr_master_parity); - if (left-- == 0) - return sprintf(page, " no_tx=%u, " - "no_rx=%u, bad_rx_aal=%u\n", lanai->stats.service_norx, - lanai->stats.service_notx, - lanai->stats.service_rxnotaal5); - if (left-- == 0) - return sprintf(page, "resets: dma=%u, card=%u\n", - lanai->stats.dma_reenable, lanai->stats.card_reset); - /* At this point, "left" should be the VCI we're looking for */ - read_lock(&vcc_sklist_lock); - for (; ; left++) { - if (left >= NUM_VCI) { - left = 0; - goto out; - } - if ((lvcc = lanai->vccs[left]) != NULL) - break; - (*pos)++; - } - /* Note that we re-use "left" here since we're done with it */ - left = sprintf(page, "VCI %4d: nref=%d, rx_nomem=%u", (vci_t) left, - lvcc->nref, lvcc->stats.rx_nomem); - if (lvcc->rx.atmvcc != NULL) { - left += sprintf(&page[left], ",\n rx_AAL=%d", - lvcc->rx.atmvcc->qos.aal == ATM_AAL5 ? 5 : 0); - if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) - left += sprintf(&page[left], ", rx_buf_size=%zu, " - "rx_bad_len=%u,\n rx_service_trash=%u, " - "rx_service_stream=%u, rx_bad_crc=%u", - lanai_buf_size(&lvcc->rx.buf), - lvcc->stats.x.aal5.rx_badlen, - lvcc->stats.x.aal5.service_trash, - lvcc->stats.x.aal5.service_stream, - lvcc->stats.x.aal5.service_rxcrc); - } - if (lvcc->tx.atmvcc != NULL) - left += sprintf(&page[left], ",\n tx_AAL=%d, " - "tx_buf_size=%zu, tx_qos=%cBR, tx_backlogged=%c", - lvcc->tx.atmvcc->qos.aal == ATM_AAL5 ? 5 : 0, - lanai_buf_size(&lvcc->tx.buf), - lvcc->tx.atmvcc == lanai->cbrvcc ? 'C' : 'U', - vcc_is_backlogged(lvcc) ? 'Y' : 'N'); - page[left++] = '\n'; - page[left] = '\0'; - out: - read_unlock(&vcc_sklist_lock); - return left; -} -#endif /* CONFIG_PROC_FS */ - -/* -------------------- HOOKS: */ - -static const struct atmdev_ops ops = { - .dev_close = lanai_dev_close, - .open = lanai_open, - .close = lanai_close, - .send = lanai_send, - .phy_put = NULL, - .phy_get = NULL, - .change_qos = lanai_change_qos, - .proc_read = lanai_proc_read, - .owner = THIS_MODULE -}; - -/* initialize one probed card */ -static int lanai_init_one(struct pci_dev *pci, - const struct pci_device_id *ident) -{ - struct lanai_dev *lanai; - struct atm_dev *atmdev; - int result; - - lanai = kzalloc_obj(*lanai); - if (lanai == NULL) { - printk(KERN_ERR DEV_LABEL - ": couldn't allocate dev_data structure!\n"); - return -ENOMEM; - } - - atmdev = atm_dev_register(DEV_LABEL, &pci->dev, &ops, -1, NULL); - if (atmdev == NULL) { - printk(KERN_ERR DEV_LABEL - ": couldn't register atm device!\n"); - kfree(lanai); - return -EBUSY; - } - - atmdev->dev_data = lanai; - lanai->pci = pci; - lanai->type = (enum lanai_type) ident->device; - - result = lanai_dev_open(atmdev); - if (result != 0) { - DPRINTK("lanai_start() failed, err=%d\n", -result); - atm_dev_deregister(atmdev); - kfree(lanai); - } - return result; -} - -static const struct pci_device_id lanai_pci_tbl[] = { - { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_LANAI2) }, - { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_LANAIHB) }, - { 0, } /* terminal entry */ -}; -MODULE_DEVICE_TABLE(pci, lanai_pci_tbl); - -static struct pci_driver lanai_driver = { - .name = DEV_LABEL, - .id_table = lanai_pci_tbl, - .probe = lanai_init_one, -}; - -module_pci_driver(lanai_driver); - -MODULE_AUTHOR("Mitchell Blank Jr "); -MODULE_DESCRIPTION("Efficient Networks Speedstream 3010 driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c deleted file mode 100644 index 24e51343df15..000000000000 --- a/drivers/atm/nicstar.c +++ /dev/null @@ -1,2759 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * nicstar.c - * - * Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards. - * - * IMPORTANT: The included file nicstarmac.c was NOT WRITTEN BY ME. - * It was taken from the frle-0.22 device driver. - * As the file doesn't have a copyright notice, in the file - * nicstarmac.copyright I put the copyright notice from the - * frle-0.22 device driver. - * Some code is based on the nicstar driver by M. Welsh. - * - * Author: Rui Prior (rprior@inescn.pt) - * PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999 - * - * - * (C) INESC 1999 - */ - -/* - * IMPORTANT INFORMATION - * - * There are currently three types of spinlocks: - * - * 1 - Per card interrupt spinlock (to protect structures and such) - * 2 - Per SCQ scq spinlock - * 3 - Per card resource spinlock (to access registers, etc.) - * - * These must NEVER be grabbed in reverse order. - * - */ - -/* Header files */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "nicstar.h" -#ifdef CONFIG_ATM_NICSTAR_USE_SUNI -#include "suni.h" -#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ -#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 -#include "idt77105.h" -#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ - -/* Additional code */ - -#include "nicstarmac.c" - -/* Configurable parameters */ - -#undef PHY_LOOPBACK -#undef TX_DEBUG -#undef RX_DEBUG -#undef GENERAL_DEBUG -#undef EXTRA_DEBUG - -/* Do not touch these */ - -#ifdef TX_DEBUG -#define TXPRINTK(args...) printk(args) -#else -#define TXPRINTK(args...) -#endif /* TX_DEBUG */ - -#ifdef RX_DEBUG -#define RXPRINTK(args...) printk(args) -#else -#define RXPRINTK(args...) -#endif /* RX_DEBUG */ - -#ifdef GENERAL_DEBUG -#define PRINTK(args...) printk(args) -#else -#define PRINTK(args...) do {} while (0) -#endif /* GENERAL_DEBUG */ - -#ifdef EXTRA_DEBUG -#define XPRINTK(args...) printk(args) -#else -#define XPRINTK(args...) -#endif /* EXTRA_DEBUG */ - -/* Macros */ - -#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ) - -#define NS_DELAY mdelay(1) - -#define PTR_DIFF(a, b) ((u32)((unsigned long)(a) - (unsigned long)(b))) - -#ifndef ATM_SKB -#define ATM_SKB(s) (&(s)->atm) -#endif - -#define scq_virt_to_bus(scq, p) \ - (scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org)) - -/* Function declarations */ - -static u32 ns_read_sram(ns_dev * card, u32 sram_address); -static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, - int count); -static int ns_init_card(int i, struct pci_dev *pcidev); -static void ns_init_card_error(ns_dev * card, int error); -static scq_info *get_scq(ns_dev *card, int size, u32 scd); -static void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc); -static void push_rxbufs(ns_dev *, struct sk_buff *); -static irqreturn_t ns_irq_handler(int irq, void *dev_id); -static int ns_open(struct atm_vcc *vcc); -static void ns_close(struct atm_vcc *vcc); -static void fill_tst(ns_dev * card, int n, vc_map * vc); -static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb); -static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, - struct sk_buff *skb, bool may_sleep); -static void process_tsq(ns_dev * card); -static void drain_scq(ns_dev * card, scq_info * scq, int pos); -static void process_rsq(ns_dev * card); -static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe); -static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb); -static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count); -static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb); -static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb); -static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb); -static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page); -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg); -#ifdef EXTRA_DEBUG -static void which_list(ns_dev * card, struct sk_buff *skb); -#endif -static void ns_poll(struct timer_list *unused); -static void ns_phy_put(struct atm_dev *dev, unsigned char value, - unsigned long addr); -static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr); - -/* Global variables */ - -static struct ns_dev *cards[NS_MAX_CARDS]; -static unsigned num_cards; -static const struct atmdev_ops atm_ops = { - .open = ns_open, - .close = ns_close, - .ioctl = ns_ioctl, - .send = ns_send, - .send_bh = ns_send_bh, - .phy_put = ns_phy_put, - .phy_get = ns_phy_get, - .proc_read = ns_proc_read, - .owner = THIS_MODULE, -}; - -static struct timer_list ns_timer; -static char *mac[NS_MAX_CARDS]; -module_param_array(mac, charp, NULL, 0); -MODULE_DESCRIPTION("ATM NIC driver for IDT 77201/77211 \"NICStAR\" and Fore ForeRunnerLE."); -MODULE_LICENSE("GPL"); - -/* Functions */ - -static int nicstar_init_one(struct pci_dev *pcidev, - const struct pci_device_id *ent) -{ - static int index = -1; - unsigned int error; - - index++; - cards[index] = NULL; - - error = ns_init_card(index, pcidev); - if (error) { - cards[index--] = NULL; /* don't increment index */ - goto err_out; - } - - return 0; -err_out: - return -ENODEV; -} - -static void nicstar_remove_one(struct pci_dev *pcidev) -{ - int i, j; - ns_dev *card = pci_get_drvdata(pcidev); - struct sk_buff *hb; - struct sk_buff *iovb; - struct sk_buff *lb; - struct sk_buff *sb; - - i = card->index; - - if (cards[i] == NULL) - return; - - if (card->atmdev->phy && card->atmdev->phy->stop) - card->atmdev->phy->stop(card->atmdev); - - /* Stop everything */ - writel(0x00000000, card->membase + CFG); - - /* De-register device */ - atm_dev_deregister(card->atmdev); - - /* Disable PCI device */ - pci_disable_device(pcidev); - - /* Free up resources */ - j = 0; - PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count); - while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) { - dev_kfree_skb_any(hb); - j++; - } - PRINTK("nicstar%d: %d huge buffers freed.\n", i, j); - j = 0; - PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, - card->iovpool.count); - while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) { - dev_kfree_skb_any(iovb); - j++; - } - PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j); - while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - dev_kfree_skb_any(lb); - while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - dev_kfree_skb_any(sb); - free_scq(card, card->scq0, NULL); - for (j = 0; j < NS_FRSCD_NUM; j++) { - if (card->scd2vc[j] != NULL) - free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc); - } - idr_destroy(&card->idr); - dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, - card->rsq.org, card->rsq.dma); - dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, - card->tsq.org, card->tsq.dma); - free_irq(card->pcidev->irq, card); - iounmap(card->membase); - kfree(card); -} - -static const struct pci_device_id nicstar_pci_tbl[] = { - { PCI_VDEVICE(IDT, PCI_DEVICE_ID_IDT_IDT77201), 0 }, - {0,} /* terminate list */ -}; - -MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl); - -static struct pci_driver nicstar_driver = { - .name = "nicstar", - .id_table = nicstar_pci_tbl, - .probe = nicstar_init_one, - .remove = nicstar_remove_one, -}; - -static int __init nicstar_init(void) -{ - unsigned error = 0; /* Initialized to remove compile warning */ - - XPRINTK("nicstar: nicstar_init() called.\n"); - - error = pci_register_driver(&nicstar_driver); - - TXPRINTK("nicstar: TX debug enabled.\n"); - RXPRINTK("nicstar: RX debug enabled.\n"); - PRINTK("nicstar: General debug enabled.\n"); -#ifdef PHY_LOOPBACK - printk("nicstar: using PHY loopback.\n"); -#endif /* PHY_LOOPBACK */ - XPRINTK("nicstar: nicstar_init() returned.\n"); - - if (!error) { - timer_setup(&ns_timer, ns_poll, 0); - ns_timer.expires = jiffies + NS_POLL_PERIOD; - add_timer(&ns_timer); - } - - return error; -} - -static void __exit nicstar_cleanup(void) -{ - XPRINTK("nicstar: nicstar_cleanup() called.\n"); - - timer_delete_sync(&ns_timer); - - pci_unregister_driver(&nicstar_driver); - - XPRINTK("nicstar: nicstar_cleanup() returned.\n"); -} - -static u32 ns_read_sram(ns_dev * card, u32 sram_address) -{ - unsigned long flags; - u32 data; - sram_address <<= 2; - sram_address &= 0x0007FFFC; /* address must be dword aligned */ - sram_address |= 0x50000000; /* SRAM read command */ - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - writel(sram_address, card->membase + CMD); - while (CMD_BUSY(card)) ; - data = readl(card->membase + DR0); - spin_unlock_irqrestore(&card->res_lock, flags); - return data; -} - -static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value, - int count) -{ - unsigned long flags; - int i, c; - count--; /* count range now is 0..3 instead of 1..4 */ - c = count; - c <<= 2; /* to use increments of 4 */ - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - for (i = 0; i <= c; i += 4) - writel(*(value++), card->membase + i); - /* Note: DR# registers are the first 4 dwords in nicstar's memspace, - so card->membase + DR0 == card->membase */ - sram_address <<= 2; - sram_address &= 0x0007FFFC; - sram_address |= (0x40000000 | count); - writel(sram_address, card->membase + CMD); - spin_unlock_irqrestore(&card->res_lock, flags); -} - -static int ns_init_card(int i, struct pci_dev *pcidev) -{ - int j; - struct ns_dev *card = NULL; - unsigned char pci_latency; - unsigned error; - u32 data; - u32 u32d[4]; - u32 ns_cfg_rctsize; - int bcount; - unsigned long membase; - - error = 0; - - if (pci_enable_device(pcidev)) { - printk("nicstar%d: can't enable PCI device\n", i); - error = 2; - ns_init_card_error(card, error); - return error; - } - if (dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING - "nicstar%d: No suitable DMA available.\n", i); - error = 2; - ns_init_card_error(card, error); - return error; - } - - card = kmalloc_obj(*card); - if (!card) { - printk - ("nicstar%d: can't allocate memory for device structure.\n", - i); - error = 2; - ns_init_card_error(card, error); - return error; - } - cards[i] = card; - spin_lock_init(&card->int_lock); - spin_lock_init(&card->res_lock); - - pci_set_drvdata(pcidev, card); - - card->index = i; - card->atmdev = NULL; - card->pcidev = pcidev; - membase = pci_resource_start(pcidev, 1); - card->membase = ioremap(membase, NS_IOREMAP_SIZE); - if (!card->membase) { - printk("nicstar%d: can't ioremap() membase.\n", i); - error = 3; - ns_init_card_error(card, error); - return error; - } - PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase); - - pci_set_master(pcidev); - - if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) { - printk("nicstar%d: can't read PCI latency timer.\n", i); - error = 6; - ns_init_card_error(card, error); - return error; - } -#ifdef NS_PCI_LATENCY - if (pci_latency < NS_PCI_LATENCY) { - PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, - NS_PCI_LATENCY); - for (j = 1; j < 4; j++) { - if (pci_write_config_byte - (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0) - break; - } - if (j == 4) { - printk - ("nicstar%d: can't set PCI latency timer to %d.\n", - i, NS_PCI_LATENCY); - error = 7; - ns_init_card_error(card, error); - return error; - } - } -#endif /* NS_PCI_LATENCY */ - - /* Clear timer overflow */ - data = readl(card->membase + STAT); - if (data & NS_STAT_TMROF) - writel(NS_STAT_TMROF, card->membase + STAT); - - /* Software reset */ - writel(NS_CFG_SWRST, card->membase + CFG); - NS_DELAY; - writel(0x00000000, card->membase + CFG); - - /* PHY reset */ - writel(0x00000008, card->membase + GP); - NS_DELAY; - writel(0x00000001, card->membase + GP); - NS_DELAY; - while (CMD_BUSY(card)) ; - writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */ - NS_DELAY; - - /* Detect PHY type */ - while (CMD_BUSY(card)) ; - writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD); - while (CMD_BUSY(card)) ; - data = readl(card->membase + DR0); - switch (data) { - case 0x00000009: - printk("nicstar%d: PHY seems to be 25 Mbps.\n", i); - card->max_pcr = ATM_25_PCR; - while (CMD_BUSY(card)) ; - writel(0x00000008, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD); - /* Clear an eventual pending interrupt */ - writel(NS_STAT_SFBQF, card->membase + STAT); -#ifdef PHY_LOOPBACK - while (CMD_BUSY(card)) ; - writel(0x00000022, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD); -#endif /* PHY_LOOPBACK */ - break; - case 0x00000030: - case 0x00000031: - printk("nicstar%d: PHY seems to be 155 Mbps.\n", i); - card->max_pcr = ATM_OC3_PCR; -#ifdef PHY_LOOPBACK - while (CMD_BUSY(card)) ; - writel(0x00000002, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD); -#endif /* PHY_LOOPBACK */ - break; - default: - printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data); - error = 8; - ns_init_card_error(card, error); - return error; - } - writel(0x00000000, card->membase + GP); - - /* Determine SRAM size */ - data = 0x76543210; - ns_write_sram(card, 0x1C003, &data, 1); - data = 0x89ABCDEF; - ns_write_sram(card, 0x14003, &data, 1); - if (ns_read_sram(card, 0x14003) == 0x89ABCDEF && - ns_read_sram(card, 0x1C003) == 0x76543210) - card->sram_size = 128; - else - card->sram_size = 32; - PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size); - - card->rct_size = NS_MAX_RCTSIZE; - -#if (NS_MAX_RCTSIZE == 4096) - if (card->sram_size == 128) - printk - ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", - i); -#elif (NS_MAX_RCTSIZE == 16384) - if (card->sram_size == 32) { - printk - ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", - i); - card->rct_size = 4096; - } -#else -#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c -#endif - - card->vpibits = NS_VPIBITS; - if (card->rct_size == 4096) - card->vcibits = 12 - NS_VPIBITS; - else /* card->rct_size == 16384 */ - card->vcibits = 14 - NS_VPIBITS; - - /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */ - if (mac[i] == NULL) - nicstar_init_eprom(card->membase); - - /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */ - writel(0x00000000, card->membase + VPM); - - card->intcnt = 0; - if (request_irq - (pcidev->irq, &ns_irq_handler, IRQF_SHARED, "nicstar", card) != 0) { - pr_err("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq); - error = 9; - ns_init_card_error(card, error); - return error; - } - - /* Initialize TSQ */ - card->tsq.org = dma_alloc_coherent(&card->pcidev->dev, - NS_TSQSIZE + NS_TSQ_ALIGNMENT, - &card->tsq.dma, GFP_KERNEL); - if (card->tsq.org == NULL) { - printk("nicstar%d: can't allocate TSQ.\n", i); - error = 10; - ns_init_card_error(card, error); - return error; - } - card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT); - card->tsq.next = card->tsq.base; - card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1); - for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++) - ns_tsi_init(card->tsq.base + j); - writel(0x00000000, card->membase + TSQH); - writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB); - PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base); - - /* Initialize RSQ */ - card->rsq.org = dma_alloc_coherent(&card->pcidev->dev, - NS_RSQSIZE + NS_RSQ_ALIGNMENT, - &card->rsq.dma, GFP_KERNEL); - if (card->rsq.org == NULL) { - printk("nicstar%d: can't allocate RSQ.\n", i); - error = 11; - ns_init_card_error(card, error); - return error; - } - card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT); - card->rsq.next = card->rsq.base; - card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1); - for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++) - ns_rsqe_init(card->rsq.base + j); - writel(0x00000000, card->membase + RSQH); - writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB); - PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base); - - /* Initialize SCQ0, the only VBR SCQ used */ - card->scq1 = NULL; - card->scq2 = NULL; - card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0); - if (card->scq0 == NULL) { - printk("nicstar%d: can't get SCQ0.\n", i); - error = 12; - ns_init_card_error(card, error); - return error; - } - u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base); - u32d[1] = (u32) 0x00000000; - u32d[2] = (u32) 0xffffffff; - u32d[3] = (u32) 0x00000000; - ns_write_sram(card, NS_VRSCD0, u32d, 4); - ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */ - ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */ - card->scq0->scd = NS_VRSCD0; - PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base); - - /* Initialize TSTs */ - card->tst_addr = NS_TST0; - card->tst_free_entries = NS_TST_NUM_ENTRIES; - data = NS_TST_OPCODE_VARIABLE; - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - ns_write_sram(card, NS_TST0 + j, &data, 1); - data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0); - ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1); - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - ns_write_sram(card, NS_TST1 + j, &data, 1); - data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1); - ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1); - for (j = 0; j < NS_TST_NUM_ENTRIES; j++) - card->tste2vc[j] = NULL; - writel(NS_TST0 << 2, card->membase + TSTB); - - /* Initialize RCT. AAL type is set on opening the VC. */ -#ifdef RCQ_SUPPORT - u32d[0] = NS_RCTE_RAWCELLINTEN; -#else - u32d[0] = 0x00000000; -#endif /* RCQ_SUPPORT */ - u32d[1] = 0x00000000; - u32d[2] = 0x00000000; - u32d[3] = 0xFFFFFFFF; - for (j = 0; j < card->rct_size; j++) - ns_write_sram(card, j * 4, u32d, 4); - - memset(card->vcmap, 0, sizeof(card->vcmap)); - - for (j = 0; j < NS_FRSCD_NUM; j++) - card->scd2vc[j] = NULL; - - /* Initialize buffer levels */ - card->sbnr.min = MIN_SB; - card->sbnr.init = NUM_SB; - card->sbnr.max = MAX_SB; - card->lbnr.min = MIN_LB; - card->lbnr.init = NUM_LB; - card->lbnr.max = MAX_LB; - card->iovnr.min = MIN_IOVB; - card->iovnr.init = NUM_IOVB; - card->iovnr.max = MAX_IOVB; - card->hbnr.min = MIN_HB; - card->hbnr.init = NUM_HB; - card->hbnr.max = MAX_HB; - - card->sm_handle = NULL; - card->sm_addr = 0x00000000; - card->lg_handle = NULL; - card->lg_addr = 0x00000000; - - card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ - - idr_init(&card->idr); - - /* Pre-allocate some huge buffers */ - skb_queue_head_init(&card->hbpool.queue); - card->hbpool.count = 0; - for (j = 0; j < NUM_HB; j++) { - struct sk_buff *hb; - hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); - if (hb == NULL) { - printk - ("nicstar%d: can't allocate %dth of %d huge buffers.\n", - i, j, NUM_HB); - error = 13; - ns_init_card_error(card, error); - return error; - } - NS_PRV_BUFTYPE(hb) = BUF_NONE; - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - } - - /* Allocate large buffers */ - skb_queue_head_init(&card->lbpool.queue); - card->lbpool.count = 0; /* Not used */ - for (j = 0; j < NUM_LB; j++) { - struct sk_buff *lb; - lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); - if (lb == NULL) { - printk - ("nicstar%d: can't allocate %dth of %d large buffers.\n", - i, j, NUM_LB); - error = 14; - ns_init_card_error(card, error); - return error; - } - NS_PRV_BUFTYPE(lb) = BUF_LG; - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, lb); - /* Due to the implementation of push_rxbufs() this is 1, not 0 */ - if (j == 1) { - card->rcbuf = lb; - card->rawcell = (struct ns_rcqe *) lb->data; - card->rawch = NS_PRV_DMA(lb); - } - } - /* Test for strange behaviour which leads to crashes */ - if ((bcount = - ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) { - printk - ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n", - i, j, bcount); - error = 14; - ns_init_card_error(card, error); - return error; - } - - /* Allocate small buffers */ - skb_queue_head_init(&card->sbpool.queue); - card->sbpool.count = 0; /* Not used */ - for (j = 0; j < NUM_SB; j++) { - struct sk_buff *sb; - sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); - if (sb == NULL) { - printk - ("nicstar%d: can't allocate %dth of %d small buffers.\n", - i, j, NUM_SB); - error = 15; - ns_init_card_error(card, error); - return error; - } - NS_PRV_BUFTYPE(sb) = BUF_SM; - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, sb); - } - /* Test for strange behaviour which leads to crashes */ - if ((bcount = - ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) { - printk - ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n", - i, j, bcount); - error = 15; - ns_init_card_error(card, error); - return error; - } - - /* Allocate iovec buffers */ - skb_queue_head_init(&card->iovpool.queue); - card->iovpool.count = 0; - for (j = 0; j < NUM_IOVB; j++) { - struct sk_buff *iovb; - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); - if (iovb == NULL) { - printk - ("nicstar%d: can't allocate %dth of %d iovec buffers.\n", - i, j, NUM_IOVB); - error = 16; - ns_init_card_error(card, error); - return error; - } - NS_PRV_BUFTYPE(iovb) = BUF_NONE; - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - } - - /* Configure NICStAR */ - if (card->rct_size == 4096) - ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES; - else /* (card->rct_size == 16384) */ - ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES; - - card->efbie = 1; - - /* Register device */ - card->atmdev = atm_dev_register("nicstar", &card->pcidev->dev, &atm_ops, - -1, NULL); - if (card->atmdev == NULL) { - printk("nicstar%d: can't register device.\n", i); - error = 17; - ns_init_card_error(card, error); - return error; - } - - if (mac[i] == NULL || !mac_pton(mac[i], card->atmdev->esi)) { - nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET, - card->atmdev->esi, 6); - if (ether_addr_equal(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00")) { - nicstar_read_eprom(card->membase, - NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT, - card->atmdev->esi, 6); - } - } - - printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi); - - card->atmdev->dev_data = card; - card->atmdev->ci_range.vpi_bits = card->vpibits; - card->atmdev->ci_range.vci_bits = card->vcibits; - card->atmdev->link_rate = card->max_pcr; - card->atmdev->phy = NULL; - -#ifdef CONFIG_ATM_NICSTAR_USE_SUNI - if (card->max_pcr == ATM_OC3_PCR) - suni_init(card->atmdev); -#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */ - -#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105 - if (card->max_pcr == ATM_25_PCR) - idt77105_init(card->atmdev); -#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */ - - if (card->atmdev->phy && card->atmdev->phy->start) - card->atmdev->phy->start(card->atmdev); - - writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */ - NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */ - NS_CFG_PHYIE, card->membase + CFG); - - num_cards++; - - return error; -} - -static void ns_init_card_error(ns_dev *card, int error) -{ - if (error >= 17) { - writel(0x00000000, card->membase + CFG); - } - if (error >= 16) { - struct sk_buff *iovb; - while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) - dev_kfree_skb_any(iovb); - } - if (error >= 15) { - struct sk_buff *sb; - while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL) - dev_kfree_skb_any(sb); - free_scq(card, card->scq0, NULL); - } - if (error >= 14) { - struct sk_buff *lb; - while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL) - dev_kfree_skb_any(lb); - } - if (error >= 13) { - struct sk_buff *hb; - while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) - dev_kfree_skb_any(hb); - } - if (error >= 12) { - dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT, - card->rsq.org, card->rsq.dma); - } - if (error >= 11) { - dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT, - card->tsq.org, card->tsq.dma); - } - if (error >= 10) { - free_irq(card->pcidev->irq, card); - } - if (error >= 4) { - iounmap(card->membase); - } - if (error >= 3) { - pci_disable_device(card->pcidev); - kfree(card); - } -} - -static scq_info *get_scq(ns_dev *card, int size, u32 scd) -{ - scq_info *scq; - - if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) - return NULL; - - scq = kmalloc_obj(*scq); - if (!scq) - return NULL; - scq->org = dma_alloc_coherent(&card->pcidev->dev, - 2 * size, &scq->dma, GFP_KERNEL); - if (!scq->org) { - kfree(scq); - return NULL; - } - scq->skb = kzalloc_objs(*scq->skb, size / NS_SCQE_SIZE); - if (!scq->skb) { - dma_free_coherent(&card->pcidev->dev, - 2 * size, scq->org, scq->dma); - kfree(scq); - return NULL; - } - scq->num_entries = size / NS_SCQE_SIZE; - scq->base = PTR_ALIGN(scq->org, size); - scq->next = scq->base; - scq->last = scq->base + (scq->num_entries - 1); - scq->tail = scq->last; - scq->scd = scd; - scq->tbd_count = 0; - init_waitqueue_head(&scq->scqfull_waitq); - scq->full = 0; - spin_lock_init(&scq->lock); - - return scq; -} - -/* For variable rate SCQ vcc must be NULL */ -static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc) -{ - int i; - - if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) - for (i = 0; i < scq->num_entries; i++) { - if (scq->skb[i] != NULL) { - vcc = ATM_SKB(scq->skb[i])->vcc; - if (vcc->pop != NULL) - vcc->pop(vcc, scq->skb[i]); - else - dev_kfree_skb_any(scq->skb[i]); - } - } else { /* vcc must be != NULL */ - - if (vcc == NULL) { - printk - ("nicstar: free_scq() called with vcc == NULL for fixed rate scq."); - for (i = 0; i < scq->num_entries; i++) - dev_kfree_skb_any(scq->skb[i]); - } else - for (i = 0; i < scq->num_entries; i++) { - if (scq->skb[i] != NULL) { - if (vcc->pop != NULL) - vcc->pop(vcc, scq->skb[i]); - else - dev_kfree_skb_any(scq->skb[i]); - } - } - } - kfree(scq->skb); - dma_free_coherent(&card->pcidev->dev, - 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ? - VBR_SCQSIZE : CBR_SCQSIZE), - scq->org, scq->dma); - kfree(scq); -} - -/* The handles passed must be pointers to the sk_buff containing the small - or large buffer(s) cast to u32. */ -static void push_rxbufs(ns_dev * card, struct sk_buff *skb) -{ - struct sk_buff *handle1, *handle2; - int id1, id2; - u32 addr1, addr2; - u32 stat; - unsigned long flags; - - /* *BARF* */ - handle2 = NULL; - addr2 = 0; - handle1 = skb; - addr1 = dma_map_single(&card->pcidev->dev, - skb->data, - (NS_PRV_BUFTYPE(skb) == BUF_SM - ? NS_SMSKBSIZE : NS_LGSKBSIZE), - DMA_TO_DEVICE); - NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */ - -#ifdef GENERAL_DEBUG - if (!addr1) - printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", - card->index); -#endif /* GENERAL_DEBUG */ - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - if (NS_PRV_BUFTYPE(skb) == BUF_SM) { - if (!addr2) { - if (card->sm_addr) { - addr2 = card->sm_addr; - handle2 = card->sm_handle; - card->sm_addr = 0x00000000; - card->sm_handle = NULL; - } else { /* (!sm_addr) */ - - card->sm_addr = addr1; - card->sm_handle = handle1; - } - } - } else { /* buf_type == BUF_LG */ - - if (!addr2) { - if (card->lg_addr) { - addr2 = card->lg_addr; - handle2 = card->lg_handle; - card->lg_addr = 0x00000000; - card->lg_handle = NULL; - } else { /* (!lg_addr) */ - - card->lg_addr = addr1; - card->lg_handle = handle1; - } - } - } - - if (addr2) { - if (NS_PRV_BUFTYPE(skb) == BUF_SM) { - if (card->sbfqc >= card->sbnr.max) { - skb_unlink(handle1, &card->sbpool.queue); - dev_kfree_skb_any(handle1); - skb_unlink(handle2, &card->sbpool.queue); - dev_kfree_skb_any(handle2); - return; - } else - card->sbfqc += 2; - } else { /* (buf_type == BUF_LG) */ - - if (card->lbfqc >= card->lbnr.max) { - skb_unlink(handle1, &card->lbpool.queue); - dev_kfree_skb_any(handle1); - skb_unlink(handle2, &card->lbpool.queue); - dev_kfree_skb_any(handle2); - return; - } else - card->lbfqc += 2; - } - - id1 = idr_alloc(&card->idr, handle1, 0, 0, GFP_ATOMIC); - if (id1 < 0) - goto out; - - id2 = idr_alloc(&card->idr, handle2, 0, 0, GFP_ATOMIC); - if (id2 < 0) - goto out; - - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - writel(addr2, card->membase + DR3); - writel(id2, card->membase + DR2); - writel(addr1, card->membase + DR1); - writel(id1, card->membase + DR0); - writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb), - card->membase + CMD); - spin_unlock_irqrestore(&card->res_lock, flags); - - XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", - card->index, - (NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"), - addr1, addr2); - } - - if (!card->efbie && card->sbfqc >= card->sbnr.min && - card->lbfqc >= card->lbnr.min) { - card->efbie = 1; - writel((readl(card->membase + CFG) | NS_CFG_EFBIE), - card->membase + CFG); - } - -out: - return; -} - -static irqreturn_t ns_irq_handler(int irq, void *dev_id) -{ - u32 stat_r; - ns_dev *card; - struct atm_dev *dev; - unsigned long flags; - - card = (ns_dev *) dev_id; - dev = card->atmdev; - card->intcnt++; - - PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index); - - spin_lock_irqsave(&card->int_lock, flags); - - stat_r = readl(card->membase + STAT); - - /* Transmit Status Indicator has been written to T. S. Queue */ - if (stat_r & NS_STAT_TSIF) { - TXPRINTK("nicstar%d: TSI interrupt\n", card->index); - process_tsq(card); - writel(NS_STAT_TSIF, card->membase + STAT); - } - - /* Incomplete CS-PDU has been transmitted */ - if (stat_r & NS_STAT_TXICP) { - writel(NS_STAT_TXICP, card->membase + STAT); - TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n", - card->index); - } - - /* Transmit Status Queue 7/8 full */ - if (stat_r & NS_STAT_TSQF) { - writel(NS_STAT_TSQF, card->membase + STAT); - PRINTK("nicstar%d: TSQ full.\n", card->index); - process_tsq(card); - } - - /* Timer overflow */ - if (stat_r & NS_STAT_TMROF) { - writel(NS_STAT_TMROF, card->membase + STAT); - PRINTK("nicstar%d: Timer overflow.\n", card->index); - } - - /* PHY device interrupt signal active */ - if (stat_r & NS_STAT_PHYI) { - writel(NS_STAT_PHYI, card->membase + STAT); - PRINTK("nicstar%d: PHY interrupt.\n", card->index); - if (dev->phy && dev->phy->interrupt) { - dev->phy->interrupt(dev); - } - } - - /* Small Buffer Queue is full */ - if (stat_r & NS_STAT_SFBQF) { - writel(NS_STAT_SFBQF, card->membase + STAT); - printk("nicstar%d: Small free buffer queue is full.\n", - card->index); - } - - /* Large Buffer Queue is full */ - if (stat_r & NS_STAT_LFBQF) { - writel(NS_STAT_LFBQF, card->membase + STAT); - printk("nicstar%d: Large free buffer queue is full.\n", - card->index); - } - - /* Receive Status Queue is full */ - if (stat_r & NS_STAT_RSQF) { - writel(NS_STAT_RSQF, card->membase + STAT); - printk("nicstar%d: RSQ full.\n", card->index); - process_rsq(card); - } - - /* Complete CS-PDU received */ - if (stat_r & NS_STAT_EOPDU) { - RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index); - process_rsq(card); - writel(NS_STAT_EOPDU, card->membase + STAT); - } - - /* Raw cell received */ - if (stat_r & NS_STAT_RAWCF) { - writel(NS_STAT_RAWCF, card->membase + STAT); -#ifndef RCQ_SUPPORT - printk("nicstar%d: Raw cell received and no support yet...\n", - card->index); -#endif /* RCQ_SUPPORT */ - /* NOTE: the following procedure may keep a raw cell pending until the - next interrupt. As this preliminary support is only meant to - avoid buffer leakage, this is not an issue. */ - while (readl(card->membase + RAWCT) != card->rawch) { - - if (ns_rcqe_islast(card->rawcell)) { - struct sk_buff *oldbuf; - - oldbuf = card->rcbuf; - card->rcbuf = idr_find(&card->idr, - ns_rcqe_nextbufhandle(card->rawcell)); - card->rawch = NS_PRV_DMA(card->rcbuf); - card->rawcell = (struct ns_rcqe *) - card->rcbuf->data; - recycle_rx_buf(card, oldbuf); - } else { - card->rawch += NS_RCQE_SIZE; - card->rawcell++; - } - } - } - - /* Small buffer queue is empty */ - if (stat_r & NS_STAT_SFBQE) { - int i; - struct sk_buff *sb; - - writel(NS_STAT_SFBQE, card->membase + STAT); - printk("nicstar%d: Small free buffer queue empty.\n", - card->index); - for (i = 0; i < card->sbnr.min; i++) { - sb = dev_alloc_skb(NS_SMSKBSIZE); - if (sb == NULL) { - writel(readl(card->membase + CFG) & - ~NS_CFG_EFBIE, card->membase + CFG); - card->efbie = 0; - break; - } - NS_PRV_BUFTYPE(sb) = BUF_SM; - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, sb); - } - card->sbfqc = i; - process_rsq(card); - } - - /* Large buffer queue empty */ - if (stat_r & NS_STAT_LFBQE) { - int i; - struct sk_buff *lb; - - writel(NS_STAT_LFBQE, card->membase + STAT); - printk("nicstar%d: Large free buffer queue empty.\n", - card->index); - for (i = 0; i < card->lbnr.min; i++) { - lb = dev_alloc_skb(NS_LGSKBSIZE); - if (lb == NULL) { - writel(readl(card->membase + CFG) & - ~NS_CFG_EFBIE, card->membase + CFG); - card->efbie = 0; - break; - } - NS_PRV_BUFTYPE(lb) = BUF_LG; - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, lb); - } - card->lbfqc = i; - process_rsq(card); - } - - /* Receive Status Queue is 7/8 full */ - if (stat_r & NS_STAT_RSQAF) { - writel(NS_STAT_RSQAF, card->membase + STAT); - RXPRINTK("nicstar%d: RSQ almost full.\n", card->index); - process_rsq(card); - } - - spin_unlock_irqrestore(&card->int_lock, flags); - PRINTK("nicstar%d: end of interrupt service\n", card->index); - return IRQ_HANDLED; -} - -static int ns_open(struct atm_vcc *vcc) -{ - ns_dev *card; - vc_map *vc; - unsigned long tmpl, modl; - int tcr, tcra; /* target cell rate, and absolute value */ - int n = 0; /* Number of entries in the TST. Initialized to remove - the compiler warning. */ - u32 u32d[4]; - int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler - warning. How I wish compilers were clever enough to - tell which variables can truly be used - uninitialized... */ - int inuse; /* tx or rx vc already in use by another vcc */ - short vpi = vcc->vpi; - int vci = vcc->vci; - - card = (ns_dev *) vcc->dev->dev_data; - PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi, - vci); - if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { - PRINTK("nicstar%d: unsupported AAL.\n", card->index); - return -EINVAL; - } - - vc = &(card->vcmap[vpi << card->vcibits | vci]); - vcc->dev_data = vc; - - inuse = 0; - if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx) - inuse = 1; - if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx) - inuse += 2; - if (inuse) { - printk("nicstar%d: %s vci already in use.\n", card->index, - inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx"); - return -EINVAL; - } - - set_bit(ATM_VF_ADDR, &vcc->flags); - - /* NOTE: You are not allowed to modify an open connection's QOS. To change - that, remove the ATM_VF_PARTIAL flag checking. There may be other changes - needed to do that. */ - if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) { - scq_info *scq; - - set_bit(ATM_VF_PARTIAL, &vcc->flags); - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - /* Check requested cell rate and availability of SCD */ - if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 - && vcc->qos.txtp.min_pcr == 0) { - PRINTK - ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n", - card->index); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -EINVAL; - } - - tcr = atm_pcr_goal(&(vcc->qos.txtp)); - tcra = tcr >= 0 ? tcr : -tcr; - - PRINTK("nicstar%d: target cell rate = %d.\n", - card->index, vcc->qos.txtp.max_pcr); - - tmpl = - (unsigned long)tcra *(unsigned long) - NS_TST_NUM_ENTRIES; - modl = tmpl % card->max_pcr; - - n = (int)(tmpl / card->max_pcr); - if (tcr > 0) { - if (modl > 0) - n++; - } else if (tcr == 0) { - if ((n = - (card->tst_free_entries - - NS_TST_RESERVED)) <= 0) { - PRINTK - ("nicstar%d: no CBR bandwidth free.\n", - card->index); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -EINVAL; - } - } - - if (n == 0) { - printk - ("nicstar%d: selected bandwidth < granularity.\n", - card->index); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -EINVAL; - } - - if (n > (card->tst_free_entries - NS_TST_RESERVED)) { - PRINTK - ("nicstar%d: not enough free CBR bandwidth.\n", - card->index); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -EINVAL; - } else - card->tst_free_entries -= n; - - XPRINTK("nicstar%d: writing %d tst entries.\n", - card->index, n); - for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) { - if (card->scd2vc[frscdi] == NULL) { - card->scd2vc[frscdi] = vc; - break; - } - } - if (frscdi == NS_FRSCD_NUM) { - PRINTK - ("nicstar%d: no SCD available for CBR channel.\n", - card->index); - card->tst_free_entries += n; - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -EBUSY; - } - - vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; - - scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd); - if (scq == NULL) { - PRINTK("nicstar%d: can't get fixed rate SCQ.\n", - card->index); - card->scd2vc[frscdi] = NULL; - card->tst_free_entries += n; - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - return -ENOMEM; - } - vc->scq = scq; - u32d[0] = scq_virt_to_bus(scq, scq->base); - u32d[1] = (u32) 0x00000000; - u32d[2] = (u32) 0xffffffff; - u32d[3] = (u32) 0x00000000; - ns_write_sram(card, vc->cbr_scd, u32d, 4); - - fill_tst(card, n, vc); - } else if (vcc->qos.txtp.traffic_class == ATM_UBR) { - vc->cbr_scd = 0x00000000; - vc->scq = card->scq0; - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - vc->tx = 1; - vc->tx_vcc = vcc; - vc->tbd_count = 0; - } - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - u32 status; - - vc->rx = 1; - vc->rx_vcc = vcc; - vc->rx_iov = NULL; - - /* Open the connection in hardware */ - if (vcc->qos.aal == ATM_AAL5) - status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN; - else /* vcc->qos.aal == ATM_AAL0 */ - status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN; -#ifdef RCQ_SUPPORT - status |= NS_RCTE_RAWCELLINTEN; -#endif /* RCQ_SUPPORT */ - ns_write_sram(card, - NS_RCT + - (vpi << card->vcibits | vci) * - NS_RCT_ENTRY_SIZE, &status, 1); - } - - } - - set_bit(ATM_VF_READY, &vcc->flags); - return 0; -} - -static void ns_close(struct atm_vcc *vcc) -{ - vc_map *vc; - ns_dev *card; - u32 data; - int i; - - vc = vcc->dev_data; - card = vcc->dev->dev_data; - PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index, - (int)vcc->vpi, vcc->vci); - - clear_bit(ATM_VF_READY, &vcc->flags); - - if (vcc->qos.rxtp.traffic_class != ATM_NONE) { - u32 addr; - unsigned long flags; - - addr = - NS_RCT + - (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE; - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - writel(NS_CMD_CLOSE_CONNECTION | addr << 2, - card->membase + CMD); - spin_unlock_irqrestore(&card->res_lock, flags); - - vc->rx = 0; - if (vc->rx_iov != NULL) { - struct sk_buff *iovb; - u32 stat; - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - PRINTK - ("nicstar%d: closing a VC with pending rx buffers.\n", - card->index); - iovb = vc->rx_iov; - recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, - NS_PRV_IOVCNT(iovb)); - NS_PRV_IOVCNT(iovb) = 0; - spin_lock_irqsave(&card->int_lock, flags); - recycle_iov_buf(card, iovb); - spin_unlock_irqrestore(&card->int_lock, flags); - vc->rx_iov = NULL; - } - } - - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - vc->tx = 0; - } - - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - unsigned long flags; - ns_scqe *scqep; - scq_info *scq; - - scq = vc->scq; - - for (;;) { - spin_lock_irqsave(&scq->lock, flags); - scqep = scq->next; - if (scqep == scq->base) - scqep = scq->last; - else - scqep--; - if (scqep == scq->tail) { - spin_unlock_irqrestore(&scq->lock, flags); - break; - } - /* If the last entry is not a TSR, place one in the SCQ in order to - be able to completely drain it and then close. */ - if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) { - ns_scqe tsr; - u32 scdi, scqi; - u32 data; - int index; - - tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); - scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; - scqi = scq->next - scq->base; - tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); - tsr.word_3 = 0x00000000; - tsr.word_4 = 0x00000000; - *scq->next = tsr; - index = (int)scqi; - scq->skb[index] = NULL; - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - data = scq_virt_to_bus(scq, scq->next); - ns_write_sram(card, scq->scd, &data, 1); - } - spin_unlock_irqrestore(&scq->lock, flags); - schedule(); - } - - /* Free all TST entries */ - data = NS_TST_OPCODE_VARIABLE; - for (i = 0; i < NS_TST_NUM_ENTRIES; i++) { - if (card->tste2vc[i] == vc) { - ns_write_sram(card, card->tst_addr + i, &data, - 1); - card->tste2vc[i] = NULL; - card->tst_free_entries++; - } - } - - card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL; - free_scq(card, vc->scq, vcc); - } - - /* remove all references to vcc before deleting it */ - if (vcc->qos.txtp.traffic_class != ATM_NONE) { - unsigned long flags; - scq_info *scq = card->scq0; - - spin_lock_irqsave(&scq->lock, flags); - - for (i = 0; i < scq->num_entries; i++) { - if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) { - ATM_SKB(scq->skb[i])->vcc = NULL; - atm_return(vcc, scq->skb[i]->truesize); - PRINTK - ("nicstar: deleted pending vcc mapping\n"); - } - } - - spin_unlock_irqrestore(&scq->lock, flags); - } - - vcc->dev_data = NULL; - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - -#ifdef RX_DEBUG - { - u32 stat, cfg; - stat = readl(card->membase + STAT); - cfg = readl(card->membase + CFG); - printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg); - printk - ("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n", - card->tsq.base, card->tsq.next, - card->tsq.last, readl(card->membase + TSQT)); - printk - ("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n", - card->rsq.base, card->rsq.next, - card->rsq.last, readl(card->membase + RSQT)); - printk("Empty free buffer queue interrupt %s \n", - card->efbie ? "enabled" : "disabled"); - printk("SBCNT = %d count = %d LBCNT = %d count = %d \n", - ns_stat_sfbqc_get(stat), card->sbpool.count, - ns_stat_lfbqc_get(stat), card->lbpool.count); - printk("hbpool.count = %d iovpool.count = %d \n", - card->hbpool.count, card->iovpool.count); - } -#endif /* RX_DEBUG */ -} - -static void fill_tst(ns_dev * card, int n, vc_map * vc) -{ - u32 new_tst; - unsigned long cl; - int e, r; - u32 data; - - /* It would be very complicated to keep the two TSTs synchronized while - assuring that writes are only made to the inactive TST. So, for now I - will use only one TST. If problems occur, I will change this again */ - - new_tst = card->tst_addr; - - /* Fill procedure */ - - for (e = 0; e < NS_TST_NUM_ENTRIES; e++) { - if (card->tste2vc[e] == NULL) - break; - } - if (e == NS_TST_NUM_ENTRIES) { - printk("nicstar%d: No free TST entries found. \n", card->index); - return; - } - - r = n; - cl = NS_TST_NUM_ENTRIES; - data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd); - - while (r > 0) { - if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) { - card->tste2vc[e] = vc; - ns_write_sram(card, new_tst + e, &data, 1); - cl -= NS_TST_NUM_ENTRIES; - r--; - } - - if (++e == NS_TST_NUM_ENTRIES) { - e = 0; - } - cl += n; - } - - /* End of fill procedure */ - - data = ns_tste_make(NS_TST_OPCODE_END, new_tst); - ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1); - ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1); - card->tst_addr = new_tst; -} - -static int _ns_send(struct atm_vcc *vcc, struct sk_buff *skb, bool may_sleep) -{ - ns_dev *card; - vc_map *vc; - scq_info *scq; - unsigned long buflen; - ns_scqe scqe; - u32 flags; /* TBD flags, not CPU flags */ - - card = vcc->dev->dev_data; - TXPRINTK("nicstar%d: ns_send() called.\n", card->index); - if ((vc = (vc_map *) vcc->dev_data) == NULL) { - printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", - card->index); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb_any(skb); - return -EINVAL; - } - - if (!vc->tx) { - printk("nicstar%d: Trying to transmit on a non-tx VC.\n", - card->index); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb_any(skb); - return -EINVAL; - } - - if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) { - printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", - card->index); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb_any(skb); - return -EINVAL; - } - - if (skb_shinfo(skb)->nr_frags != 0) { - printk("nicstar%d: No scatter-gather yet.\n", card->index); - atomic_inc(&vcc->stats->tx_err); - dev_kfree_skb_any(skb); - return -EINVAL; - } - - ATM_SKB(skb)->vcc = vcc; - - NS_PRV_DMA(skb) = dma_map_single(&card->pcidev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - - if (vcc->qos.aal == ATM_AAL5) { - buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */ - flags = NS_TBD_AAL5; - scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb)); - scqe.word_3 = cpu_to_le32(skb->len); - scqe.word_4 = - ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0, - ATM_SKB(skb)-> - atm_options & ATM_ATMOPT_CLP ? 1 : 0); - flags |= NS_TBD_EOPDU; - } else { /* (vcc->qos.aal == ATM_AAL0) */ - - buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */ - flags = NS_TBD_AAL0; - scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER); - scqe.word_3 = cpu_to_le32(0x00000000); - if (*skb->data & 0x02) /* Payload type 1 - end of pdu */ - flags |= NS_TBD_EOPDU; - scqe.word_4 = - cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK); - /* Force the VPI/VCI to be the same as in VCC struct */ - scqe.word_4 |= - cpu_to_le32((((u32) vcc-> - vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc-> - vci) << - NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK); - } - - if (vcc->qos.txtp.traffic_class == ATM_CBR) { - scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen); - scq = ((vc_map *) vcc->dev_data)->scq; - } else { - scqe.word_1 = - ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen); - scq = card->scq0; - } - - if (push_scqe(card, vc, scq, &scqe, skb, may_sleep) != 0) { - atomic_inc(&vcc->stats->tx_err); - dma_unmap_single(&card->pcidev->dev, NS_PRV_DMA(skb), skb->len, - DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - return -EIO; - } - atomic_inc(&vcc->stats->tx); - - return 0; -} - -static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - return _ns_send(vcc, skb, true); -} - -static int ns_send_bh(struct atm_vcc *vcc, struct sk_buff *skb) -{ - return _ns_send(vcc, skb, false); -} - -static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, - struct sk_buff *skb, bool may_sleep) -{ - unsigned long flags; - ns_scqe tsr; - u32 scdi, scqi; - int scq_is_vbr; - u32 data; - int index; - - spin_lock_irqsave(&scq->lock, flags); - while (scq->tail == scq->next) { - if (!may_sleep) { - spin_unlock_irqrestore(&scq->lock, flags); - printk("nicstar%d: Error pushing TBD.\n", card->index); - return 1; - } - - scq->full = 1; - wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, - scq->tail != scq->next, - scq->lock, - SCQFULL_TIMEOUT); - - if (scq->full) { - spin_unlock_irqrestore(&scq->lock, flags); - printk("nicstar%d: Timeout pushing TBD.\n", - card->index); - return 1; - } - } - *scq->next = *tbd; - index = (int)(scq->next - scq->base); - scq->skb[index] = skb; - XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n", - card->index, skb, index); - XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", - card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2), - le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4), - scq->next); - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - - vc->tbd_count++; - if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) { - scq->tbd_count++; - scq_is_vbr = 1; - } else - scq_is_vbr = 0; - - if (vc->tbd_count >= MAX_TBD_PER_VC - || scq->tbd_count >= MAX_TBD_PER_SCQ) { - int has_run = 0; - - while (scq->tail == scq->next) { - if (!may_sleep) { - data = scq_virt_to_bus(scq, scq->next); - ns_write_sram(card, scq->scd, &data, 1); - spin_unlock_irqrestore(&scq->lock, flags); - printk("nicstar%d: Error pushing TSR.\n", - card->index); - return 0; - } - - scq->full = 1; - if (has_run++) - break; - wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, - scq->tail != scq->next, - scq->lock, - SCQFULL_TIMEOUT); - } - - if (!scq->full) { - tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE); - if (scq_is_vbr) - scdi = NS_TSR_SCDISVBR; - else - scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE; - scqi = scq->next - scq->base; - tsr.word_2 = ns_tsr_mkword_2(scdi, scqi); - tsr.word_3 = 0x00000000; - tsr.word_4 = 0x00000000; - - *scq->next = tsr; - index = (int)scqi; - scq->skb[index] = NULL; - XPRINTK - ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n", - card->index, le32_to_cpu(tsr.word_1), - le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3), - le32_to_cpu(tsr.word_4), scq->next); - if (scq->next == scq->last) - scq->next = scq->base; - else - scq->next++; - vc->tbd_count = 0; - scq->tbd_count = 0; - } else - PRINTK("nicstar%d: Timeout pushing TSR.\n", - card->index); - } - data = scq_virt_to_bus(scq, scq->next); - ns_write_sram(card, scq->scd, &data, 1); - - spin_unlock_irqrestore(&scq->lock, flags); - - return 0; -} - -static void process_tsq(ns_dev * card) -{ - u32 scdi; - scq_info *scq; - ns_tsi *previous = NULL, *one_ahead, *two_ahead; - int serviced_entries; /* flag indicating at least on entry was serviced */ - - serviced_entries = 0; - - if (card->tsq.next == card->tsq.last) - one_ahead = card->tsq.base; - else - one_ahead = card->tsq.next + 1; - - if (one_ahead == card->tsq.last) - two_ahead = card->tsq.base; - else - two_ahead = one_ahead + 1; - - while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) || - !ns_tsi_isempty(two_ahead)) - /* At most two empty, as stated in the 77201 errata */ - { - serviced_entries = 1; - - /* Skip the one or two possible empty entries */ - while (ns_tsi_isempty(card->tsq.next)) { - if (card->tsq.next == card->tsq.last) - card->tsq.next = card->tsq.base; - else - card->tsq.next++; - } - - if (!ns_tsi_tmrof(card->tsq.next)) { - scdi = ns_tsi_getscdindex(card->tsq.next); - if (scdi == NS_TSI_SCDISVBR) - scq = card->scq0; - else { - if (card->scd2vc[scdi] == NULL) { - printk - ("nicstar%d: could not find VC from SCD index.\n", - card->index); - ns_tsi_init(card->tsq.next); - return; - } - scq = card->scd2vc[scdi]->scq; - } - drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next)); - scq->full = 0; - wake_up_interruptible(&(scq->scqfull_waitq)); - } - - ns_tsi_init(card->tsq.next); - previous = card->tsq.next; - if (card->tsq.next == card->tsq.last) - card->tsq.next = card->tsq.base; - else - card->tsq.next++; - - if (card->tsq.next == card->tsq.last) - one_ahead = card->tsq.base; - else - one_ahead = card->tsq.next + 1; - - if (one_ahead == card->tsq.last) - two_ahead = card->tsq.base; - else - two_ahead = one_ahead + 1; - } - - if (serviced_entries) - writel(PTR_DIFF(previous, card->tsq.base), - card->membase + TSQH); -} - -static void drain_scq(ns_dev * card, scq_info * scq, int pos) -{ - struct atm_vcc *vcc; - struct sk_buff *skb; - int i; - unsigned long flags; - - XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n", - card->index, scq, pos); - if (pos >= scq->num_entries) { - printk("nicstar%d: Bad index on drain_scq().\n", card->index); - return; - } - - spin_lock_irqsave(&scq->lock, flags); - i = (int)(scq->tail - scq->base); - if (++i == scq->num_entries) - i = 0; - while (i != pos) { - skb = scq->skb[i]; - XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n", - card->index, skb, i); - if (skb != NULL) { - dma_unmap_single(&card->pcidev->dev, - NS_PRV_DMA(skb), - skb->len, - DMA_TO_DEVICE); - vcc = ATM_SKB(skb)->vcc; - if (vcc && vcc->pop != NULL) { - vcc->pop(vcc, skb); - } else { - dev_kfree_skb_irq(skb); - } - scq->skb[i] = NULL; - } - if (++i == scq->num_entries) - i = 0; - } - scq->tail = scq->base + pos; - spin_unlock_irqrestore(&scq->lock, flags); -} - -static void process_rsq(ns_dev * card) -{ - ns_rsqe *previous; - - if (!ns_rsqe_valid(card->rsq.next)) - return; - do { - dequeue_rx(card, card->rsq.next); - ns_rsqe_init(card->rsq.next); - previous = card->rsq.next; - if (card->rsq.next == card->rsq.last) - card->rsq.next = card->rsq.base; - else - card->rsq.next++; - } while (ns_rsqe_valid(card->rsq.next)); - writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH); -} - -static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe) -{ - u32 vpi, vci; - vc_map *vc; - struct sk_buff *iovb; - struct iovec *iov; - struct atm_vcc *vcc; - struct sk_buff *skb; - unsigned short aal5_len; - int len; - u32 stat; - u32 id; - - stat = readl(card->membase + STAT); - card->sbfqc = ns_stat_sfbqc_get(stat); - card->lbfqc = ns_stat_lfbqc_get(stat); - - id = le32_to_cpu(rsqe->buffer_handle); - skb = idr_remove(&card->idr, id); - if (!skb) { - RXPRINTK(KERN_ERR - "nicstar%d: skb not found!\n", card->index); - return; - } - dma_sync_single_for_cpu(&card->pcidev->dev, - NS_PRV_DMA(skb), - (NS_PRV_BUFTYPE(skb) == BUF_SM - ? NS_SMSKBSIZE : NS_LGSKBSIZE), - DMA_FROM_DEVICE); - dma_unmap_single(&card->pcidev->dev, - NS_PRV_DMA(skb), - (NS_PRV_BUFTYPE(skb) == BUF_SM - ? NS_SMSKBSIZE : NS_LGSKBSIZE), - DMA_FROM_DEVICE); - vpi = ns_rsqe_vpi(rsqe); - vci = ns_rsqe_vci(rsqe); - if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) { - printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n", - card->index, vpi, vci); - recycle_rx_buf(card, skb); - return; - } - - vc = &(card->vcmap[vpi << card->vcibits | vci]); - if (!vc->rx) { - RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n", - card->index, vpi, vci); - recycle_rx_buf(card, skb); - return; - } - - vcc = vc->rx_vcc; - - if (vcc->qos.aal == ATM_AAL0) { - struct sk_buff *sb; - unsigned char *cell; - int i; - - cell = skb->data; - for (i = ns_rsqe_cellcount(rsqe); i; i--) { - sb = dev_alloc_skb(NS_SMSKBSIZE); - if (!sb) { - printk - ("nicstar%d: Can't allocate buffers for aal0.\n", - card->index); - atomic_add(i, &vcc->stats->rx_drop); - break; - } - if (!atm_charge(vcc, sb->truesize)) { - RXPRINTK - ("nicstar%d: atm_charge() dropped aal0 packets.\n", - card->index); - atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */ - dev_kfree_skb_any(sb); - break; - } - /* Rebuild the header */ - *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 | - (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000); - if (i == 1 && ns_rsqe_eopdu(rsqe)) - *((u32 *) sb->data) |= 0x00000002; - skb_put(sb, NS_AAL0_HEADER); - memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD); - skb_put(sb, ATM_CELL_PAYLOAD); - ATM_SKB(sb)->vcc = vcc; - __net_timestamp(sb); - vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); - cell += ATM_CELL_PAYLOAD; - } - - recycle_rx_buf(card, skb); - return; - } - - /* To reach this point, the AAL layer can only be AAL5 */ - - if ((iovb = vc->rx_iov) == NULL) { - iovb = skb_dequeue(&(card->iovpool.queue)); - if (iovb == NULL) { /* No buffers in the queue */ - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC); - if (iovb == NULL) { - printk("nicstar%d: Out of iovec buffers.\n", - card->index); - atomic_inc(&vcc->stats->rx_drop); - recycle_rx_buf(card, skb); - return; - } - NS_PRV_BUFTYPE(iovb) = BUF_NONE; - } else if (--card->iovpool.count < card->iovnr.min) { - struct sk_buff *new_iovb; - if ((new_iovb = - alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) { - NS_PRV_BUFTYPE(iovb) = BUF_NONE; - skb_queue_tail(&card->iovpool.queue, new_iovb); - card->iovpool.count++; - } - } - vc->rx_iov = iovb; - NS_PRV_IOVCNT(iovb) = 0; - iovb->len = 0; - iovb->data = iovb->head; - skb_reset_tail_pointer(iovb); - /* IMPORTANT: a pointer to the sk_buff containing the small or large - buffer is stored as iovec base, NOT a pointer to the - small or large buffer itself. */ - } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) { - printk("nicstar%d: received too big AAL5 SDU.\n", card->index); - atomic_inc(&vcc->stats->rx_err); - recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, - NS_MAX_IOVECS); - NS_PRV_IOVCNT(iovb) = 0; - iovb->len = 0; - iovb->data = iovb->head; - skb_reset_tail_pointer(iovb); - } - iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++]; - iov->iov_base = (void *)skb; - iov->iov_len = ns_rsqe_cellcount(rsqe) * 48; - iovb->len += iov->iov_len; - -#ifdef EXTRA_DEBUG - if (NS_PRV_IOVCNT(iovb) == 1) { - if (NS_PRV_BUFTYPE(skb) != BUF_SM) { - printk - ("nicstar%d: Expected a small buffer, and this is not one.\n", - card->index); - which_list(card, skb); - atomic_inc(&vcc->stats->rx_err); - recycle_rx_buf(card, skb); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - } else { /* NS_PRV_IOVCNT(iovb) >= 2 */ - - if (NS_PRV_BUFTYPE(skb) != BUF_LG) { - printk - ("nicstar%d: Expected a large buffer, and this is not one.\n", - card->index); - which_list(card, skb); - atomic_inc(&vcc->stats->rx_err); - recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, - NS_PRV_IOVCNT(iovb)); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - } -#endif /* EXTRA_DEBUG */ - - if (ns_rsqe_eopdu(rsqe)) { - /* This works correctly regardless of the endianness of the host */ - unsigned char *L1L2 = (unsigned char *) - (skb->data + iov->iov_len - 6); - aal5_len = L1L2[0] << 8 | L1L2[1]; - len = (aal5_len == 0x0000) ? 0x10000 : aal5_len; - if (ns_rsqe_crcerr(rsqe) || - len + 8 > iovb->len || len + (47 + 8) < iovb->len) { - printk("nicstar%d: AAL5 CRC error", card->index); - if (len + 8 > iovb->len || len + (47 + 8) < iovb->len) - printk(" - PDU size mismatch.\n"); - else - printk(".\n"); - atomic_inc(&vcc->stats->rx_err); - recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data, - NS_PRV_IOVCNT(iovb)); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } - - /* By this point we (hopefully) have a complete SDU without errors. */ - - if (NS_PRV_IOVCNT(iovb) == 1) { /* Just a small buffer */ - /* skb points to a small buffer */ - if (!atm_charge(vcc, skb->truesize)) { - push_rxbufs(card, skb); - atomic_inc(&vcc->stats->rx_drop); - } else { - skb_put(skb, len); - dequeue_sm_buf(card, skb); - ATM_SKB(skb)->vcc = vcc; - __net_timestamp(skb); - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - } - } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */ - struct sk_buff *sb; - - sb = (struct sk_buff *)(iov - 1)->iov_base; - /* skb points to a large buffer */ - - if (len <= NS_SMBUFSIZE) { - if (!atm_charge(vcc, sb->truesize)) { - push_rxbufs(card, sb); - atomic_inc(&vcc->stats->rx_drop); - } else { - skb_put(sb, len); - dequeue_sm_buf(card, sb); - ATM_SKB(sb)->vcc = vcc; - __net_timestamp(sb); - vcc->push(vcc, sb); - atomic_inc(&vcc->stats->rx); - } - - push_rxbufs(card, skb); - - } else { /* len > NS_SMBUFSIZE, the usual case */ - - if (!atm_charge(vcc, skb->truesize)) { - push_rxbufs(card, skb); - atomic_inc(&vcc->stats->rx_drop); - } else { - dequeue_lg_buf(card, skb); - skb_push(skb, NS_SMBUFSIZE); - skb_copy_from_linear_data(sb, skb->data, - NS_SMBUFSIZE); - skb_put(skb, len - NS_SMBUFSIZE); - ATM_SKB(skb)->vcc = vcc; - __net_timestamp(skb); - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - } - - push_rxbufs(card, sb); - - } - - } else { /* Must push a huge buffer */ - - struct sk_buff *hb, *sb, *lb; - int remaining, tocopy; - int j; - - hb = skb_dequeue(&(card->hbpool.queue)); - if (hb == NULL) { /* No buffers in the queue */ - - hb = dev_alloc_skb(NS_HBUFSIZE); - if (hb == NULL) { - printk - ("nicstar%d: Out of huge buffers.\n", - card->index); - atomic_inc(&vcc->stats->rx_drop); - recycle_iovec_rx_bufs(card, - (struct iovec *) - iovb->data, - NS_PRV_IOVCNT(iovb)); - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - return; - } else if (card->hbpool.count < card->hbnr.min) { - struct sk_buff *new_hb; - if ((new_hb = - dev_alloc_skb(NS_HBUFSIZE)) != - NULL) { - skb_queue_tail(&card->hbpool. - queue, new_hb); - card->hbpool.count++; - } - } - NS_PRV_BUFTYPE(hb) = BUF_NONE; - } else if (--card->hbpool.count < card->hbnr.min) { - struct sk_buff *new_hb; - if ((new_hb = - dev_alloc_skb(NS_HBUFSIZE)) != NULL) { - NS_PRV_BUFTYPE(new_hb) = BUF_NONE; - skb_queue_tail(&card->hbpool.queue, - new_hb); - card->hbpool.count++; - } - if (card->hbpool.count < card->hbnr.min) { - if ((new_hb = - dev_alloc_skb(NS_HBUFSIZE)) != - NULL) { - NS_PRV_BUFTYPE(new_hb) = - BUF_NONE; - skb_queue_tail(&card->hbpool. - queue, new_hb); - card->hbpool.count++; - } - } - } - - iov = (struct iovec *)iovb->data; - - if (!atm_charge(vcc, hb->truesize)) { - recycle_iovec_rx_bufs(card, iov, - NS_PRV_IOVCNT(iovb)); - if (card->hbpool.count < card->hbnr.max) { - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - } else - dev_kfree_skb_any(hb); - atomic_inc(&vcc->stats->rx_drop); - } else { - /* Copy the small buffer to the huge buffer */ - sb = (struct sk_buff *)iov->iov_base; - skb_copy_from_linear_data(sb, hb->data, - iov->iov_len); - skb_put(hb, iov->iov_len); - remaining = len - iov->iov_len; - iov++; - /* Free the small buffer */ - push_rxbufs(card, sb); - - /* Copy all large buffers to the huge buffer and free them */ - for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) { - lb = (struct sk_buff *)iov->iov_base; - tocopy = - min_t(int, remaining, iov->iov_len); - skb_copy_from_linear_data(lb, - skb_tail_pointer - (hb), tocopy); - skb_put(hb, tocopy); - iov++; - remaining -= tocopy; - push_rxbufs(card, lb); - } -#ifdef EXTRA_DEBUG - if (remaining != 0 || hb->len != len) - printk - ("nicstar%d: Huge buffer len mismatch.\n", - card->index); -#endif /* EXTRA_DEBUG */ - ATM_SKB(hb)->vcc = vcc; - __net_timestamp(hb); - vcc->push(vcc, hb); - atomic_inc(&vcc->stats->rx); - } - } - - vc->rx_iov = NULL; - recycle_iov_buf(card, iovb); - } - -} - -static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb) -{ - if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) { - printk("nicstar%d: What kind of rx buffer is this?\n", - card->index); - dev_kfree_skb_any(skb); - } else - push_rxbufs(card, skb); -} - -static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count) -{ - while (count-- > 0) - recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base); -} - -static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb) -{ - if (card->iovpool.count < card->iovnr.max) { - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - } else - dev_kfree_skb_any(iovb); -} - -static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb) -{ - skb_unlink(sb, &card->sbpool.queue); - if (card->sbfqc < card->sbnr.init) { - struct sk_buff *new_sb; - if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { - NS_PRV_BUFTYPE(new_sb) = BUF_SM; - skb_queue_tail(&card->sbpool.queue, new_sb); - skb_reserve(new_sb, NS_AAL0_HEADER); - push_rxbufs(card, new_sb); - } - } - if (card->sbfqc < card->sbnr.init) - { - struct sk_buff *new_sb; - if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) { - NS_PRV_BUFTYPE(new_sb) = BUF_SM; - skb_queue_tail(&card->sbpool.queue, new_sb); - skb_reserve(new_sb, NS_AAL0_HEADER); - push_rxbufs(card, new_sb); - } - } -} - -static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb) -{ - skb_unlink(lb, &card->lbpool.queue); - if (card->lbfqc < card->lbnr.init) { - struct sk_buff *new_lb; - if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { - NS_PRV_BUFTYPE(new_lb) = BUF_LG; - skb_queue_tail(&card->lbpool.queue, new_lb); - skb_reserve(new_lb, NS_SMBUFSIZE); - push_rxbufs(card, new_lb); - } - } - if (card->lbfqc < card->lbnr.init) - { - struct sk_buff *new_lb; - if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) { - NS_PRV_BUFTYPE(new_lb) = BUF_LG; - skb_queue_tail(&card->lbpool.queue, new_lb); - skb_reserve(new_lb, NS_SMBUFSIZE); - push_rxbufs(card, new_lb); - } - } -} - -static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page) -{ - u32 stat; - ns_dev *card; - int left; - - left = (int)*pos; - card = (ns_dev *) dev->dev_data; - stat = readl(card->membase + STAT); - if (!left--) - return sprintf(page, "Pool count min init max \n"); - if (!left--) - return sprintf(page, "Small %5d %5d %5d %5d \n", - ns_stat_sfbqc_get(stat), card->sbnr.min, - card->sbnr.init, card->sbnr.max); - if (!left--) - return sprintf(page, "Large %5d %5d %5d %5d \n", - ns_stat_lfbqc_get(stat), card->lbnr.min, - card->lbnr.init, card->lbnr.max); - if (!left--) - return sprintf(page, "Huge %5d %5d %5d %5d \n", - card->hbpool.count, card->hbnr.min, - card->hbnr.init, card->hbnr.max); - if (!left--) - return sprintf(page, "Iovec %5d %5d %5d %5d \n", - card->iovpool.count, card->iovnr.min, - card->iovnr.init, card->iovnr.max); - if (!left--) { - int retval; - retval = - sprintf(page, "Interrupt counter: %u \n", card->intcnt); - card->intcnt = 0; - return retval; - } -#if 0 - /* Dump 25.6 Mbps PHY registers */ - /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it - here just in case it's needed for debugging. */ - if (card->max_pcr == ATM_25_PCR && !left--) { - u32 phy_regs[4]; - u32 i; - - for (i = 0; i < 4; i++) { - while (CMD_BUSY(card)) ; - writel(NS_CMD_READ_UTILITY | 0x00000200 | i, - card->membase + CMD); - while (CMD_BUSY(card)) ; - phy_regs[i] = readl(card->membase + DR0) & 0x000000FF; - } - - return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n", - phy_regs[0], phy_regs[1], phy_regs[2], - phy_regs[3]); - } -#endif /* 0 - Dump 25.6 Mbps PHY registers */ -#if 0 - /* Dump TST */ - if (left-- < NS_TST_NUM_ENTRIES) { - if (card->tste2vc[left + 1] == NULL) - return sprintf(page, "%5d - VBR/UBR \n", left + 1); - else - return sprintf(page, "%5d - %d %d \n", left + 1, - card->tste2vc[left + 1]->tx_vcc->vpi, - card->tste2vc[left + 1]->tx_vcc->vci); - } -#endif /* 0 */ - return 0; -} - -static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg) -{ - ns_dev *card; - pool_levels pl; - long btype; - unsigned long flags; - - card = dev->dev_data; - switch (cmd) { - case NS_GETPSTAT: - if (get_user - (pl.buftype, &((pool_levels __user *) arg)->buftype)) - return -EFAULT; - switch (pl.buftype) { - case NS_BUFTYPE_SMALL: - pl.count = - ns_stat_sfbqc_get(readl(card->membase + STAT)); - pl.level.min = card->sbnr.min; - pl.level.init = card->sbnr.init; - pl.level.max = card->sbnr.max; - break; - - case NS_BUFTYPE_LARGE: - pl.count = - ns_stat_lfbqc_get(readl(card->membase + STAT)); - pl.level.min = card->lbnr.min; - pl.level.init = card->lbnr.init; - pl.level.max = card->lbnr.max; - break; - - case NS_BUFTYPE_HUGE: - pl.count = card->hbpool.count; - pl.level.min = card->hbnr.min; - pl.level.init = card->hbnr.init; - pl.level.max = card->hbnr.max; - break; - - case NS_BUFTYPE_IOVEC: - pl.count = card->iovpool.count; - pl.level.min = card->iovnr.min; - pl.level.init = card->iovnr.init; - pl.level.max = card->iovnr.max; - break; - - default: - return -ENOIOCTLCMD; - - } - if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl))) - return (sizeof(pl)); - else - return -EFAULT; - - case NS_SETBUFLEV: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl))) - return -EFAULT; - if (pl.level.min >= pl.level.init - || pl.level.init >= pl.level.max) - return -EINVAL; - if (pl.level.min == 0) - return -EINVAL; - switch (pl.buftype) { - case NS_BUFTYPE_SMALL: - if (pl.level.max > TOP_SB) - return -EINVAL; - card->sbnr.min = pl.level.min; - card->sbnr.init = pl.level.init; - card->sbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_LARGE: - if (pl.level.max > TOP_LB) - return -EINVAL; - card->lbnr.min = pl.level.min; - card->lbnr.init = pl.level.init; - card->lbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_HUGE: - if (pl.level.max > TOP_HB) - return -EINVAL; - card->hbnr.min = pl.level.min; - card->hbnr.init = pl.level.init; - card->hbnr.max = pl.level.max; - break; - - case NS_BUFTYPE_IOVEC: - if (pl.level.max > TOP_IOVB) - return -EINVAL; - card->iovnr.min = pl.level.min; - card->iovnr.init = pl.level.init; - card->iovnr.max = pl.level.max; - break; - - default: - return -EINVAL; - - } - return 0; - - case NS_ADJBUFLEV: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - btype = (long)arg; /* a long is the same size as a pointer or bigger */ - switch (btype) { - case NS_BUFTYPE_SMALL: - while (card->sbfqc < card->sbnr.init) { - struct sk_buff *sb; - - sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL); - if (sb == NULL) - return -ENOMEM; - NS_PRV_BUFTYPE(sb) = BUF_SM; - skb_queue_tail(&card->sbpool.queue, sb); - skb_reserve(sb, NS_AAL0_HEADER); - push_rxbufs(card, sb); - } - break; - - case NS_BUFTYPE_LARGE: - while (card->lbfqc < card->lbnr.init) { - struct sk_buff *lb; - - lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL); - if (lb == NULL) - return -ENOMEM; - NS_PRV_BUFTYPE(lb) = BUF_LG; - skb_queue_tail(&card->lbpool.queue, lb); - skb_reserve(lb, NS_SMBUFSIZE); - push_rxbufs(card, lb); - } - break; - - case NS_BUFTYPE_HUGE: - while (card->hbpool.count > card->hbnr.init) { - struct sk_buff *hb; - - spin_lock_irqsave(&card->int_lock, flags); - hb = skb_dequeue(&card->hbpool.queue); - card->hbpool.count--; - spin_unlock_irqrestore(&card->int_lock, flags); - if (hb == NULL) - printk - ("nicstar%d: huge buffer count inconsistent.\n", - card->index); - else - dev_kfree_skb_any(hb); - - } - while (card->hbpool.count < card->hbnr.init) { - struct sk_buff *hb; - - hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL); - if (hb == NULL) - return -ENOMEM; - NS_PRV_BUFTYPE(hb) = BUF_NONE; - spin_lock_irqsave(&card->int_lock, flags); - skb_queue_tail(&card->hbpool.queue, hb); - card->hbpool.count++; - spin_unlock_irqrestore(&card->int_lock, flags); - } - break; - - case NS_BUFTYPE_IOVEC: - while (card->iovpool.count > card->iovnr.init) { - struct sk_buff *iovb; - - spin_lock_irqsave(&card->int_lock, flags); - iovb = skb_dequeue(&card->iovpool.queue); - card->iovpool.count--; - spin_unlock_irqrestore(&card->int_lock, flags); - if (iovb == NULL) - printk - ("nicstar%d: iovec buffer count inconsistent.\n", - card->index); - else - dev_kfree_skb_any(iovb); - - } - while (card->iovpool.count < card->iovnr.init) { - struct sk_buff *iovb; - - iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL); - if (iovb == NULL) - return -ENOMEM; - NS_PRV_BUFTYPE(iovb) = BUF_NONE; - spin_lock_irqsave(&card->int_lock, flags); - skb_queue_tail(&card->iovpool.queue, iovb); - card->iovpool.count++; - spin_unlock_irqrestore(&card->int_lock, flags); - } - break; - - default: - return -EINVAL; - - } - return 0; - - default: - if (dev->phy && dev->phy->ioctl) { - return dev->phy->ioctl(dev, cmd, arg); - } else { - printk("nicstar%d: %s == NULL \n", card->index, - dev->phy ? "dev->phy->ioctl" : "dev->phy"); - return -ENOIOCTLCMD; - } - } -} - -#ifdef EXTRA_DEBUG -static void which_list(ns_dev * card, struct sk_buff *skb) -{ - printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb)); -} -#endif /* EXTRA_DEBUG */ - -static void ns_poll(struct timer_list *unused) -{ - int i; - ns_dev *card; - unsigned long flags; - u32 stat_r, stat_w; - - PRINTK("nicstar: Entering ns_poll().\n"); - for (i = 0; i < num_cards; i++) { - card = cards[i]; - if (!spin_trylock_irqsave(&card->int_lock, flags)) { - /* Probably it isn't worth spinning */ - continue; - } - - stat_w = 0; - stat_r = readl(card->membase + STAT); - if (stat_r & NS_STAT_TSIF) - stat_w |= NS_STAT_TSIF; - if (stat_r & NS_STAT_EOPDU) - stat_w |= NS_STAT_EOPDU; - - process_tsq(card); - process_rsq(card); - - writel(stat_w, card->membase + STAT); - spin_unlock_irqrestore(&card->int_lock, flags); - } - mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD); - PRINTK("nicstar: Leaving ns_poll().\n"); -} - -static void ns_phy_put(struct atm_dev *dev, unsigned char value, - unsigned long addr) -{ - ns_dev *card; - unsigned long flags; - - card = dev->dev_data; - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - writel((u32) value, card->membase + DR0); - writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF), - card->membase + CMD); - spin_unlock_irqrestore(&card->res_lock, flags); -} - -static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr) -{ - ns_dev *card; - unsigned long flags; - u32 data; - - card = dev->dev_data; - spin_lock_irqsave(&card->res_lock, flags); - while (CMD_BUSY(card)) ; - writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF), - card->membase + CMD); - while (CMD_BUSY(card)) ; - data = readl(card->membase + DR0) & 0x000000FF; - spin_unlock_irqrestore(&card->res_lock, flags); - return (unsigned char)data; -} - -module_init(nicstar_init); -module_exit(nicstar_cleanup); diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c deleted file mode 100644 index 791f69a07ddf..000000000000 --- a/drivers/atm/nicstarmac.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * this file included by nicstar.c - */ - -/* - * nicstarmac.c - * Read this ForeRunner's MAC address from eprom/eeprom - */ - -#include - -typedef void __iomem *virt_addr_t; - -#define CYCLE_DELAY 5 - -#define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \ - udelay((useconds));} -/* - * The following tables represent the timing diagrams found in - * the Data Sheet for the Xicor X25020 EEProm. The #defines below - * represent the bits in the NICStAR's General Purpose register - * that must be toggled for the corresponding actions on the EEProm - * to occur. - */ - -/* Write Data To EEProm from SI line on rising edge of CLK */ -/* Read Data From EEProm on falling edge of CLK */ - -#define CS_HIGH 0x0002 /* Chip select high */ -#define CS_LOW 0x0000 /* Chip select low (active low) */ -#define CLK_HIGH 0x0004 /* Clock high */ -#define CLK_LOW 0x0000 /* Clock low */ -#define SI_HIGH 0x0001 /* Serial input data high */ -#define SI_LOW 0x0000 /* Serial input data low */ - -/* Read Status Register = 0000 0101b */ -#if 0 -static u_int32_t rdsrtab[] = { - CS_HIGH | CLK_HIGH, - CS_LOW | CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH, /* 1 */ - CLK_LOW | SI_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH /* 1 */ -}; -#endif /* 0 */ - -/* Read from EEPROM = 0000 0011b */ -static u_int32_t readtab[] = { - /* - CS_HIGH | CLK_HIGH, - */ - CS_LOW | CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW, - CLK_HIGH, /* 0 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH, /* 1 */ - CLK_LOW | SI_HIGH, - CLK_HIGH | SI_HIGH /* 1 */ -}; - -/* Clock to read from/write to the eeprom */ -static u_int32_t clocktab[] = { - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW, - CLK_HIGH, - CLK_LOW -}; - -#define NICSTAR_REG_WRITE(bs, reg, val) \ - while ( readl(bs + STAT) & 0x0200 ) ; \ - writel((val),(base)+(reg)) -#define NICSTAR_REG_READ(bs, reg) \ - readl((base)+(reg)) -#define NICSTAR_REG_GENERAL_PURPOSE GP - -/* - * This routine will clock the Read_Status_reg function into the X2520 - * eeprom, then pull the result from bit 16 of the NicSTaR's General Purpose - * register. - */ -#if 0 -u_int32_t nicstar_read_eprom_status(virt_addr_t base) -{ - u_int32_t val; - u_int32_t rbyte; - int32_t i, j; - - /* Send read instruction */ - val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; - - for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) { - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | rdsrtab[i])); - osp_MicroDelay(CYCLE_DELAY); - } - - /* Done sending instruction - now pull data off of bit 16, MSB first */ - /* Data clocked out of eeprom on falling edge of clock */ - - rbyte = 0; - for (i = 7, j = 0; i >= 0; i--) { - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++])); - rbyte |= (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) - & 0x00010000) >> 16) << i); - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++])); - osp_MicroDelay(CYCLE_DELAY); - } - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2); - osp_MicroDelay(CYCLE_DELAY); - return rbyte; -} -#endif /* 0 */ - -/* - * This routine will clock the Read_data function into the X2520 - * eeprom, followed by the address to read from, through the NicSTaR's General - * Purpose register. - */ - -static u_int8_t read_eprom_byte(virt_addr_t base, u_int8_t offset) -{ - u_int32_t val = 0; - int i, j = 0; - u_int8_t tempread = 0; - - val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; - - /* Send READ instruction */ - for (i = 0; i < ARRAY_SIZE(readtab); i++) { - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | readtab[i])); - osp_MicroDelay(CYCLE_DELAY); - } - - /* Next, we need to send the byte address to read from */ - for (i = 7; i >= 0; i--) { - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++] | ((offset >> i) & 1))); - osp_MicroDelay(CYCLE_DELAY); - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++] | ((offset >> i) & 1))); - osp_MicroDelay(CYCLE_DELAY); - } - - j = 0; - - /* Now, we can read data from the eeprom by clocking it in */ - for (i = 7; i >= 0; i--) { - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++])); - osp_MicroDelay(CYCLE_DELAY); - tempread |= - (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) - & 0x00010000) >> 16) << i); - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | clocktab[j++])); - osp_MicroDelay(CYCLE_DELAY); - } - - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2); - osp_MicroDelay(CYCLE_DELAY); - return tempread; -} - -static void nicstar_init_eprom(virt_addr_t base) -{ - u_int32_t val; - - /* - * turn chip select off - */ - val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0; - - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | CS_HIGH | CLK_HIGH)); - osp_MicroDelay(CYCLE_DELAY); - - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | CS_HIGH | CLK_LOW)); - osp_MicroDelay(CYCLE_DELAY); - - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | CS_HIGH | CLK_HIGH)); - osp_MicroDelay(CYCLE_DELAY); - - NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, - (val | CS_HIGH | CLK_LOW)); - osp_MicroDelay(CYCLE_DELAY); -} - -/* - * This routine will be the interface to the ReadPromByte function - * above. - */ - -static void -nicstar_read_eprom(virt_addr_t base, - u_int8_t prom_offset, u_int8_t * buffer, u_int32_t nbytes) -{ - u_int i; - - for (i = 0; i < nbytes; i++) { - buffer[i] = read_eprom_byte(base, prom_offset); - ++prom_offset; - osp_MicroDelay(CYCLE_DELAY); - } -} diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c deleted file mode 100644 index 1830d1b8619f..000000000000 --- a/drivers/atm/solos-attrlist.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -SOLOS_ATTR_RO(DriverVersion) -SOLOS_ATTR_RO(APIVersion) -SOLOS_ATTR_RO(FirmwareVersion) -SOLOS_ATTR_RO(Version) -// SOLOS_ATTR_RO(DspVersion) -// SOLOS_ATTR_RO(CommonHandshake) -SOLOS_ATTR_RO(Connected) -SOLOS_ATTR_RO(OperationalMode) -SOLOS_ATTR_RO(State) -SOLOS_ATTR_RO(Watchdog) -SOLOS_ATTR_RO(OperationProgress) -SOLOS_ATTR_RO(LastFailed) -SOLOS_ATTR_RO(TxBitRate) -SOLOS_ATTR_RO(RxBitRate) -// SOLOS_ATTR_RO(DeltACTATPds) -// SOLOS_ATTR_RO(DeltACTATPus) -SOLOS_ATTR_RO(TxATTNDR) -SOLOS_ATTR_RO(RxATTNDR) -SOLOS_ATTR_RO(AnnexType) -SOLOS_ATTR_RO(GeneralFailure) -SOLOS_ATTR_RO(InterleaveDpDn) -SOLOS_ATTR_RO(InterleaveDpUp) -SOLOS_ATTR_RO(RSCorrectedErrorsDn) -SOLOS_ATTR_RO(RSUnCorrectedErrorsDn) -SOLOS_ATTR_RO(RSCorrectedErrorsUp) -SOLOS_ATTR_RO(RSUnCorrectedErrorsUp) -SOLOS_ATTR_RO(InterleaveRDn) -SOLOS_ATTR_RO(InterleaveRUp) -SOLOS_ATTR_RO(BisRDn) -SOLOS_ATTR_RO(BisRUp) -SOLOS_ATTR_RO(INPdown) -SOLOS_ATTR_RO(INPup) -SOLOS_ATTR_RO(ShowtimeStart) -SOLOS_ATTR_RO(ATURVendor) -SOLOS_ATTR_RO(ATUCCountry) -SOLOS_ATTR_RO(ATURANSIRev) -SOLOS_ATTR_RO(ATURANSISTD) -SOLOS_ATTR_RO(ATUCANSIRev) -SOLOS_ATTR_RO(ATUCANSIId) -SOLOS_ATTR_RO(ATUCANSISTD) -SOLOS_ATTR_RO(DataBoost) -SOLOS_ATTR_RO(LocalITUCountryCode) -SOLOS_ATTR_RO(LocalSEF) -SOLOS_ATTR_RO(LocalEndLOS) -SOLOS_ATTR_RO(LocalSNRMargin) -SOLOS_ATTR_RO(LocalLineAttn) -SOLOS_ATTR_RO(RawAttn) -SOLOS_ATTR_RO(LocalTxPower) -SOLOS_ATTR_RO(RemoteTxPower) -SOLOS_ATTR_RO(RemoteSEF) -SOLOS_ATTR_RO(RemoteLOS) -SOLOS_ATTR_RO(RemoteLineAttn) -SOLOS_ATTR_RO(RemoteSNRMargin) -SOLOS_ATTR_RO(LineUpCount) -SOLOS_ATTR_RO(SRACnt) -SOLOS_ATTR_RO(SRACntUp) -SOLOS_ATTR_RO(ProfileStatus) -SOLOS_ATTR_RW(Action) -SOLOS_ATTR_RW(ActivateLine) -SOLOS_ATTR_RO(LineStatus) -SOLOS_ATTR_RW(HostControl) -SOLOS_ATTR_RW(AutoStart) -SOLOS_ATTR_RW(Failsafe) -SOLOS_ATTR_RW(ShowtimeLed) -SOLOS_ATTR_RW(Retrain) -SOLOS_ATTR_RW(Defaults) -SOLOS_ATTR_RW(LineMode) -SOLOS_ATTR_RW(Profile) -SOLOS_ATTR_RW(DetectNoise) -SOLOS_ATTR_RW(BisAForceSNRMarginDn) -SOLOS_ATTR_RW(BisMForceSNRMarginDn) -SOLOS_ATTR_RW(BisAMaxMargin) -SOLOS_ATTR_RW(BisMMaxMargin) -SOLOS_ATTR_RW(AnnexAForceSNRMarginDn) -SOLOS_ATTR_RW(AnnexAMaxMargin) -SOLOS_ATTR_RW(AnnexMMaxMargin) -SOLOS_ATTR_RO(SupportedAnnexes) -SOLOS_ATTR_RO(Status) -SOLOS_ATTR_RO(TotalStart) -SOLOS_ATTR_RO(RecentShowtimeStart) -SOLOS_ATTR_RO(TotalRxBlocks) -SOLOS_ATTR_RO(TotalTxBlocks) diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c deleted file mode 100644 index 24c764664c24..000000000000 --- a/drivers/atm/solos-pci.c +++ /dev/null @@ -1,1496 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for the Solos PCI ADSL2+ card, designed to support Linux by - * Traverse Technologies -- https://www.traverse.com.au/ - * Xrio Limited -- http://www.xrio.com/ - * - * Copyright © 2008 Traverse Technologies - * Copyright © 2008 Intel Corporation - * - * Authors: Nathan Williams - * David Woodhouse - * Treker Chen - */ - -#define DEBUG -#define VERBOSE_DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VERSION "1.04" -#define DRIVER_VERSION 0x01 -#define PTAG "solos-pci" - -#define CONFIG_RAM_SIZE 128 -#define FLAGS_ADDR 0x7C -#define IRQ_EN_ADDR 0x78 -#define FPGA_VER 0x74 -#define IRQ_CLEAR 0x70 -#define WRITE_FLASH 0x6C -#define PORTS 0x68 -#define FLASH_BLOCK 0x64 -#define FLASH_BUSY 0x60 -#define FPGA_MODE 0x5C -#define FLASH_MODE 0x58 -#define GPIO_STATUS 0x54 -#define DRIVER_VER 0x50 -#define TX_DMA_ADDR(port) (0x40 + (4 * (port))) -#define RX_DMA_ADDR(port) (0x30 + (4 * (port))) - -#define DATA_RAM_SIZE 32768 -#define BUF_SIZE 2048 -#define OLD_BUF_SIZE 4096 /* For FPGA versions <= 2*/ -/* Old boards use ATMEL AD45DB161D flash */ -#define ATMEL_FPGA_PAGE 528 /* FPGA flash page size*/ -#define ATMEL_SOLOS_PAGE 512 /* Solos flash page size*/ -#define ATMEL_FPGA_BLOCK (ATMEL_FPGA_PAGE * 8) /* FPGA block size*/ -#define ATMEL_SOLOS_BLOCK (ATMEL_SOLOS_PAGE * 8) /* Solos block size*/ -/* Current boards use M25P/M25PE SPI flash */ -#define SPI_FLASH_BLOCK (256 * 64) - -#define RX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2) -#define TX_BUF(card, nr) ((card->buffers) + (nr)*(card->buffer_size)*2 + (card->buffer_size)) -#define FLASH_BUF ((card->buffers) + 4*(card->buffer_size)*2) - -#define RX_DMA_SIZE 2048 - -#define FPGA_VERSION(a,b) (((a) << 8) + (b)) -#define LEGACY_BUFFERS 2 -#define DMA_SUPPORTED 4 - -static int reset = 0; -static int atmdebug = 0; -static int firmware_upgrade = 0; -static int fpga_upgrade = 0; -static int db_firmware_upgrade = 0; -static int db_fpga_upgrade = 0; - -struct pkt_hdr { - __le16 size; - __le16 vpi; - __le16 vci; - __le16 type; -}; - -struct solos_skb_cb { - struct atm_vcc *vcc; - uint32_t dma_addr; -}; - - -#define SKB_CB(skb) ((struct solos_skb_cb *)skb->cb) - -#define PKT_DATA 0 -#define PKT_COMMAND 1 -#define PKT_POPEN 3 -#define PKT_PCLOSE 4 -#define PKT_STATUS 5 - -struct solos_card { - void __iomem *config_regs; - void __iomem *buffers; - int nr_ports; - int tx_mask; - struct pci_dev *dev; - struct atm_dev *atmdev[4]; - struct tasklet_struct tlet; - spinlock_t tx_lock; - spinlock_t tx_queue_lock; - spinlock_t cli_queue_lock; - spinlock_t param_queue_lock; - struct list_head param_queue; - struct sk_buff_head tx_queue[4]; - struct sk_buff_head cli_queue[4]; - struct sk_buff *tx_skb[4]; - struct sk_buff *rx_skb[4]; - unsigned char *dma_bounce; - wait_queue_head_t param_wq; - wait_queue_head_t fw_wq; - int using_dma; - int dma_alignment; - int fpga_version; - int buffer_size; - int atmel_flash; -}; - - -struct solos_param { - struct list_head list; - pid_t pid; - int port; - struct sk_buff *response; -}; - -#define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) - -MODULE_AUTHOR("Traverse Technologies "); -MODULE_DESCRIPTION("Solos PCI driver"); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("solos-FPGA.bin"); -MODULE_FIRMWARE("solos-Firmware.bin"); -MODULE_FIRMWARE("solos-db-FPGA.bin"); -MODULE_PARM_DESC(reset, "Reset Solos chips on startup"); -MODULE_PARM_DESC(atmdebug, "Print ATM data"); -MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); -MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade"); -MODULE_PARM_DESC(db_firmware_upgrade, "Initiate daughter board Solos firmware upgrade"); -MODULE_PARM_DESC(db_fpga_upgrade, "Initiate daughter board FPGA upgrade"); -module_param(reset, int, 0444); -module_param(atmdebug, int, 0644); -module_param(firmware_upgrade, int, 0444); -module_param(fpga_upgrade, int, 0444); -module_param(db_firmware_upgrade, int, 0444); -module_param(db_fpga_upgrade, int, 0444); - -static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, - struct atm_vcc *vcc); -static uint32_t fpga_tx(struct solos_card *); -static irqreturn_t solos_irq(int irq, void *dev_id); -static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); -static int atm_init(struct solos_card *, struct device *); -static void atm_remove(struct solos_card *); -static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); -static void solos_bh(unsigned long); -static int print_buffer(struct sk_buff *buf); - -static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); -} - -static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); - struct solos_card *card = atmdev->dev_data; - struct solos_param prm; - struct sk_buff *skb; - struct pkt_hdr *header; - int buflen; - - buflen = strlen(attr->attr.name) + 10; - - skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); - if (!skb) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n"); - return -ENOMEM; - } - - header = skb_put(skb, sizeof(*header)); - - buflen = snprintf((void *)&header[1], buflen - 1, - "L%05d\n%s\n", current->pid, attr->attr.name); - skb_put(skb, buflen); - - header->size = cpu_to_le16(buflen); - header->vpi = cpu_to_le16(0); - header->vci = cpu_to_le16(0); - header->type = cpu_to_le16(PKT_COMMAND); - - prm.pid = current->pid; - prm.response = NULL; - prm.port = SOLOS_CHAN(atmdev); - - spin_lock_irq(&card->param_queue_lock); - list_add(&prm.list, &card->param_queue); - spin_unlock_irq(&card->param_queue_lock); - - fpga_queue(card, prm.port, skb, NULL); - - wait_event_timeout(card->param_wq, prm.response, 5 * HZ); - - spin_lock_irq(&card->param_queue_lock); - list_del(&prm.list); - spin_unlock_irq(&card->param_queue_lock); - - if (!prm.response) - return -EIO; - - buflen = prm.response->len; - memcpy(buf, prm.response->data, buflen); - kfree_skb(prm.response); - - return buflen; -} - -static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); - struct solos_card *card = atmdev->dev_data; - struct solos_param prm; - struct sk_buff *skb; - struct pkt_hdr *header; - int buflen; - ssize_t ret; - - buflen = strlen(attr->attr.name) + 11 + count; - - skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL); - if (!skb) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n"); - return -ENOMEM; - } - - header = skb_put(skb, sizeof(*header)); - - buflen = snprintf((void *)&header[1], buflen - 1, - "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf); - - skb_put(skb, buflen); - header->size = cpu_to_le16(buflen); - header->vpi = cpu_to_le16(0); - header->vci = cpu_to_le16(0); - header->type = cpu_to_le16(PKT_COMMAND); - - prm.pid = current->pid; - prm.response = NULL; - prm.port = SOLOS_CHAN(atmdev); - - spin_lock_irq(&card->param_queue_lock); - list_add(&prm.list, &card->param_queue); - spin_unlock_irq(&card->param_queue_lock); - - fpga_queue(card, prm.port, skb, NULL); - - wait_event_timeout(card->param_wq, prm.response, 5 * HZ); - - spin_lock_irq(&card->param_queue_lock); - list_del(&prm.list); - spin_unlock_irq(&card->param_queue_lock); - - skb = prm.response; - - if (!skb) - return -EIO; - - buflen = skb->len; - - /* Sometimes it has a newline, sometimes it doesn't. */ - if (skb->data[buflen - 1] == '\n') - buflen--; - - if (buflen == 2 && !strncmp(skb->data, "OK", 2)) - ret = count; - else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5)) - ret = -EIO; - else { - /* We know we have enough space allocated for this; we allocated - it ourselves */ - skb->data[buflen] = 0; - - dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n", - skb->data); - ret = -EIO; - } - kfree_skb(skb); - - return ret; -} - -static char *next_string(struct sk_buff *skb) -{ - int i = 0; - char *this = skb->data; - - for (i = 0; i < skb->len; i++) { - if (this[i] == '\n') { - this[i] = 0; - skb_pull(skb, i + 1); - return this; - } - if (!isprint(this[i])) - return NULL; - } - return NULL; -} - -/* - * Status packet has fields separated by \n, starting with a version number - * for the information therein. Fields are.... - * - * packet version - * RxBitRate (version >= 1) - * TxBitRate (version >= 1) - * State (version >= 1) - * LocalSNRMargin (version >= 1) - * LocalLineAttn (version >= 1) - */ -static int process_status(struct solos_card *card, int port, struct sk_buff *skb) -{ - char *str, *state_str, *snr, *attn; - int ver, rate_up, rate_down, err; - - if (!card->atmdev[port]) - return -ENODEV; - - str = next_string(skb); - if (!str) - return -EIO; - - err = kstrtoint(str, 10, &ver); - if (err) { - dev_warn(&card->dev->dev, "Unexpected status interrupt version\n"); - return err; - } - if (ver < 1) { - dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n", - ver); - return -EIO; - } - - str = next_string(skb); - if (!str) - return -EIO; - if (!strcmp(str, "ERROR")) { - dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n", - port); - return 0; - } - - err = kstrtoint(str, 10, &rate_down); - if (err) - return err; - - str = next_string(skb); - if (!str) - return -EIO; - err = kstrtoint(str, 10, &rate_up); - if (err) - return err; - - state_str = next_string(skb); - if (!state_str) - return -EIO; - - /* Anything but 'Showtime' is down */ - if (strcmp(state_str, "Showtime")) { - atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_LOST); - dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str); - return 0; - } - - snr = next_string(skb); - if (!snr) - return -EIO; - attn = next_string(skb); - if (!attn) - return -EIO; - - dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n", - port, state_str, rate_down/1000, rate_up/1000, - snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn); - - card->atmdev[port]->link_rate = rate_down / 424; - atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_FOUND); - - return 0; -} - -static int process_command(struct solos_card *card, int port, struct sk_buff *skb) -{ - struct solos_param *prm; - unsigned long flags; - int cmdpid; - int found = 0, err; - - if (skb->len < 7) - return 0; - - if (skb->data[0] != 'L' || !isdigit(skb->data[1]) || - !isdigit(skb->data[2]) || !isdigit(skb->data[3]) || - !isdigit(skb->data[4]) || !isdigit(skb->data[5]) || - skb->data[6] != '\n') - return 0; - - err = kstrtoint(&skb->data[1], 10, &cmdpid); - if (err) - return err; - - spin_lock_irqsave(&card->param_queue_lock, flags); - list_for_each_entry(prm, &card->param_queue, list) { - if (prm->port == port && prm->pid == cmdpid) { - prm->response = skb; - skb_pull(skb, 7); - wake_up(&card->param_wq); - found = 1; - break; - } - } - spin_unlock_irqrestore(&card->param_queue_lock, flags); - return found; -} - -static ssize_t console_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); - struct solos_card *card = atmdev->dev_data; - struct sk_buff *skb; - unsigned int len; - - spin_lock_bh(&card->cli_queue_lock); - skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); - spin_unlock_bh(&card->cli_queue_lock); - if(skb == NULL) - return sprintf(buf, "No data.\n"); - - len = skb->len; - memcpy(buf, skb->data, len); - - kfree_skb(skb); - return len; -} - -static int send_command(struct solos_card *card, int dev, const char *buf, size_t size) -{ - struct sk_buff *skb; - struct pkt_hdr *header; - - if (size > (BUF_SIZE - sizeof(*header))) { - dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); - return 0; - } - skb = alloc_skb(size + sizeof(*header), GFP_ATOMIC); - if (!skb) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in send_command()\n"); - return 0; - } - - header = skb_put(skb, sizeof(*header)); - - header->size = cpu_to_le16(size); - header->vpi = cpu_to_le16(0); - header->vci = cpu_to_le16(0); - header->type = cpu_to_le16(PKT_COMMAND); - - skb_put_data(skb, buf, size); - - fpga_queue(card, dev, skb, NULL); - - return 0; -} - -static ssize_t console_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); - struct solos_card *card = atmdev->dev_data; - int err; - - err = send_command(card, SOLOS_CHAN(atmdev), buf, count); - - return err?:count; -} - -struct geos_gpio_attr { - struct device_attribute attr; - int offset; -}; - -#define SOLOS_GPIO_ATTR(_name, _mode, _show, _store, _offset) \ - struct geos_gpio_attr gpio_attr_##_name = { \ - .attr = __ATTR(_name, _mode, _show, _store), \ - .offset = _offset } - -static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = dev_get_drvdata(dev); - uint32_t data32; - - if (count != 1 && (count != 2 || buf[1] != '\n')) - return -EINVAL; - - spin_lock_irq(&card->param_queue_lock); - data32 = ioread32(card->config_regs + GPIO_STATUS); - if (buf[0] == '1') { - data32 |= 1 << gattr->offset; - iowrite32(data32, card->config_regs + GPIO_STATUS); - } else if (buf[0] == '0') { - data32 &= ~(1 << gattr->offset); - iowrite32(data32, card->config_regs + GPIO_STATUS); - } else { - count = -EINVAL; - } - spin_unlock_irq(&card->param_queue_lock); - return count; -} - -static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = dev_get_drvdata(dev); - uint32_t data32; - - data32 = ioread32(card->config_regs + GPIO_STATUS); - data32 = (data32 >> gattr->offset) & 1; - - return sprintf(buf, "%d\n", data32); -} - -static ssize_t hardware_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); - struct solos_card *card = dev_get_drvdata(dev); - uint32_t data32; - - data32 = ioread32(card->config_regs + GPIO_STATUS); - switch (gattr->offset) { - case 0: - /* HardwareVersion */ - data32 = data32 & 0x1F; - break; - case 1: - /* HardwareVariant */ - data32 = (data32 >> 5) & 0x0F; - break; - } - return sprintf(buf, "%d\n", data32); -} - -static DEVICE_ATTR_RW(console); - - -#define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL); -#define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store); - -#include "solos-attrlist.c" - -static SOLOS_GPIO_ATTR(GPIO1, 0644, geos_gpio_show, geos_gpio_store, 9); -static SOLOS_GPIO_ATTR(GPIO2, 0644, geos_gpio_show, geos_gpio_store, 10); -static SOLOS_GPIO_ATTR(GPIO3, 0644, geos_gpio_show, geos_gpio_store, 11); -static SOLOS_GPIO_ATTR(GPIO4, 0644, geos_gpio_show, geos_gpio_store, 12); -static SOLOS_GPIO_ATTR(GPIO5, 0644, geos_gpio_show, geos_gpio_store, 13); -static SOLOS_GPIO_ATTR(PushButton, 0444, geos_gpio_show, NULL, 14); -static SOLOS_GPIO_ATTR(HardwareVersion, 0444, hardware_show, NULL, 0); -static SOLOS_GPIO_ATTR(HardwareVariant, 0444, hardware_show, NULL, 1); -#undef SOLOS_ATTR_RO -#undef SOLOS_ATTR_RW - -#define SOLOS_ATTR_RO(x) &dev_attr_##x.attr, -#define SOLOS_ATTR_RW(x) &dev_attr_##x.attr, - -static struct attribute *solos_attrs[] = { -#include "solos-attrlist.c" - NULL -}; - -static const struct attribute_group solos_attr_group = { - .attrs = solos_attrs, - .name = "parameters", -}; - -static struct attribute *gpio_attrs[] = { - &gpio_attr_GPIO1.attr.attr, - &gpio_attr_GPIO2.attr.attr, - &gpio_attr_GPIO3.attr.attr, - &gpio_attr_GPIO4.attr.attr, - &gpio_attr_GPIO5.attr.attr, - &gpio_attr_PushButton.attr.attr, - &gpio_attr_HardwareVersion.attr.attr, - &gpio_attr_HardwareVariant.attr.attr, - NULL -}; - -static const struct attribute_group gpio_attr_group = { - .attrs = gpio_attrs, - .name = "gpio", -}; - -static int flash_upgrade(struct solos_card *card, int chip) -{ - const struct firmware *fw; - const char *fw_name; - int blocksize = 0; - int numblocks = 0; - int offset; - - switch (chip) { - case 0: - fw_name = "solos-FPGA.bin"; - if (card->atmel_flash) - blocksize = ATMEL_FPGA_BLOCK; - else - blocksize = SPI_FLASH_BLOCK; - break; - case 1: - fw_name = "solos-Firmware.bin"; - if (card->atmel_flash) - blocksize = ATMEL_SOLOS_BLOCK; - else - blocksize = SPI_FLASH_BLOCK; - break; - case 2: - if (card->fpga_version > LEGACY_BUFFERS){ - fw_name = "solos-db-FPGA.bin"; - if (card->atmel_flash) - blocksize = ATMEL_FPGA_BLOCK; - else - blocksize = SPI_FLASH_BLOCK; - } else { - dev_info(&card->dev->dev, "FPGA version doesn't support" - " daughter board upgrades\n"); - return -EPERM; - } - break; - case 3: - if (card->fpga_version > LEGACY_BUFFERS){ - fw_name = "solos-Firmware.bin"; - if (card->atmel_flash) - blocksize = ATMEL_SOLOS_BLOCK; - else - blocksize = SPI_FLASH_BLOCK; - } else { - dev_info(&card->dev->dev, "FPGA version doesn't support" - " daughter board upgrades\n"); - return -EPERM; - } - break; - default: - return -ENODEV; - } - - if (request_firmware(&fw, fw_name, &card->dev->dev)) - return -ENOENT; - - dev_info(&card->dev->dev, "Flash upgrade starting\n"); - - /* New FPGAs require driver version before permitting flash upgrades */ - iowrite32(DRIVER_VERSION, card->config_regs + DRIVER_VER); - - numblocks = fw->size / blocksize; - dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size); - dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks); - - dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); - iowrite32(1, card->config_regs + FPGA_MODE); - (void) ioread32(card->config_regs + FPGA_MODE); - - /* Set mode to Chip Erase */ - if(chip == 0 || chip == 2) - dev_info(&card->dev->dev, "Set FPGA Flash mode to FPGA Chip Erase\n"); - if(chip == 1 || chip == 3) - dev_info(&card->dev->dev, "Set FPGA Flash mode to Solos Chip Erase\n"); - iowrite32((chip * 2), card->config_regs + FLASH_MODE); - - - iowrite32(1, card->config_regs + WRITE_FLASH); - wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); - - for (offset = 0; offset < fw->size; offset += blocksize) { - int i; - - /* Clear write flag */ - iowrite32(0, card->config_regs + WRITE_FLASH); - - /* Set mode to Block Write */ - /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */ - iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE); - - /* Copy block to buffer, swapping each 16 bits for Atmel flash */ - for(i = 0; i < blocksize; i += 4) { - uint32_t word; - if (card->atmel_flash) - word = swahb32p((uint32_t *)(fw->data + offset + i)); - else - word = *(uint32_t *)(fw->data + offset + i); - if(card->fpga_version > LEGACY_BUFFERS) - iowrite32(word, FLASH_BUF + i); - else - iowrite32(word, RX_BUF(card, 3) + i); - } - - /* Specify block number and then trigger flash write */ - iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK); - iowrite32(1, card->config_regs + WRITE_FLASH); - wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY)); - } - - release_firmware(fw); - iowrite32(0, card->config_regs + WRITE_FLASH); - iowrite32(0, card->config_regs + FPGA_MODE); - iowrite32(0, card->config_regs + FLASH_MODE); - dev_info(&card->dev->dev, "Returning FPGA to Data mode\n"); - return 0; -} - -static irqreturn_t solos_irq(int irq, void *dev_id) -{ - struct solos_card *card = dev_id; - int handled = 1; - - iowrite32(0, card->config_regs + IRQ_CLEAR); - - /* If we're up and running, just kick the tasklet to process TX/RX */ - if (card->atmdev[0]) - tasklet_schedule(&card->tlet); - else - wake_up(&card->fw_wq); - - return IRQ_RETVAL(handled); -} - -static void solos_bh(unsigned long card_arg) -{ - struct solos_card *card = (void *)card_arg; - uint32_t card_flags; - uint32_t rx_done = 0; - int port; - - /* - * Since fpga_tx() is going to need to read the flags under its lock, - * it can return them to us so that we don't have to hit PCI MMIO - * again for the same information - */ - card_flags = fpga_tx(card); - - for (port = 0; port < card->nr_ports; port++) { - if (card_flags & (0x10 << port)) { - struct pkt_hdr _hdr, *header; - struct sk_buff *skb; - struct atm_vcc *vcc; - int size; - - if (card->using_dma) { - skb = card->rx_skb[port]; - card->rx_skb[port] = NULL; - - dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, - RX_DMA_SIZE, DMA_FROM_DEVICE); - - header = (void *)skb->data; - size = le16_to_cpu(header->size); - skb_put(skb, size + sizeof(*header)); - skb_pull(skb, sizeof(*header)); - } else { - header = &_hdr; - - rx_done |= 0x10 << port; - - memcpy_fromio(header, RX_BUF(card, port), sizeof(*header)); - - size = le16_to_cpu(header->size); - if (size > (card->buffer_size - sizeof(*header))){ - dev_warn(&card->dev->dev, "Invalid buffer size\n"); - continue; - } - - /* Use netdev_alloc_skb() because it adds NET_SKB_PAD of - * headroom, and ensures we can route packets back out an - * Ethernet interface (for example) without having to - * reallocate. Adding NET_IP_ALIGN also ensures that both - * PPPoATM and PPPoEoBR2684 packets end up aligned. */ - skb = netdev_alloc_skb_ip_align(NULL, size + 1); - if (!skb) { - if (net_ratelimit()) - dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); - continue; - } - - memcpy_fromio(skb_put(skb, size), - RX_BUF(card, port) + sizeof(*header), - size); - } - if (atmdebug) { - dev_info(&card->dev->dev, "Received: port %d\n", port); - dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", - size, le16_to_cpu(header->vpi), - le16_to_cpu(header->vci)); - print_buffer(skb); - } - - switch (le16_to_cpu(header->type)) { - case PKT_DATA: - vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi), - le16_to_cpu(header->vci)); - if (!vcc) { - if (net_ratelimit()) - dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", - le16_to_cpu(header->vpi), le16_to_cpu(header->vci), - port); - dev_kfree_skb_any(skb); - break; - } - atm_charge(vcc, skb->truesize); - vcc->push(vcc, skb); - atomic_inc(&vcc->stats->rx); - break; - - case PKT_STATUS: - if (process_status(card, port, skb) && - net_ratelimit()) { - dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port); - print_buffer(skb); - } - dev_kfree_skb_any(skb); - break; - - case PKT_COMMAND: - default: /* FIXME: Not really, surely? */ - if (process_command(card, port, skb)) - break; - spin_lock(&card->cli_queue_lock); - if (skb_queue_len(&card->cli_queue[port]) > 10) { - if (net_ratelimit()) - dev_warn(&card->dev->dev, "Dropping console response on port %d\n", - port); - dev_kfree_skb_any(skb); - } else - skb_queue_tail(&card->cli_queue[port], skb); - spin_unlock(&card->cli_queue_lock); - break; - } - } - /* Allocate RX skbs for any ports which need them */ - if (card->using_dma && card->atmdev[port] && - !card->rx_skb[port]) { - /* Unlike the MMIO case (qv) we can't add NET_IP_ALIGN - * here; the FPGA can only DMA to addresses which are - * aligned to 4 bytes. */ - struct sk_buff *skb = dev_alloc_skb(RX_DMA_SIZE); - if (skb) { - SKB_CB(skb)->dma_addr = - dma_map_single(&card->dev->dev, skb->data, - RX_DMA_SIZE, DMA_FROM_DEVICE); - iowrite32(SKB_CB(skb)->dma_addr, - card->config_regs + RX_DMA_ADDR(port)); - card->rx_skb[port] = skb; - } else { - if (net_ratelimit()) - dev_warn(&card->dev->dev, "Failed to allocate RX skb"); - - /* We'll have to try again later */ - tasklet_schedule(&card->tlet); - } - } - } - if (rx_done) - iowrite32(rx_done, card->config_regs + FLAGS_ADDR); - - return; -} - -static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) -{ - struct hlist_head *head; - struct atm_vcc *vcc = NULL; - struct sock *s; - - read_lock(&vcc_sklist_lock); - head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; - sk_for_each(s, head) { - vcc = atm_sk(s); - if (vcc->dev == dev && vcc->vci == vci && - vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE && - test_bit(ATM_VF_READY, &vcc->flags)) - goto out; - } - vcc = NULL; - out: - read_unlock(&vcc_sklist_lock); - return vcc; -} - -static int popen(struct atm_vcc *vcc) -{ - struct solos_card *card = vcc->dev->dev_data; - struct sk_buff *skb; - struct pkt_hdr *header; - - if (vcc->qos.aal != ATM_AAL5) { - dev_warn(&card->dev->dev, "Unsupported ATM type %d\n", - vcc->qos.aal); - return -EINVAL; - } - - skb = alloc_skb(sizeof(*header), GFP_KERNEL); - if (!skb) { - if (net_ratelimit()) - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); - return -ENOMEM; - } - header = skb_put(skb, sizeof(*header)); - - header->size = cpu_to_le16(0); - header->vpi = cpu_to_le16(vcc->vpi); - header->vci = cpu_to_le16(vcc->vci); - header->type = cpu_to_le16(PKT_POPEN); - - fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); - - set_bit(ATM_VF_ADDR, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - return 0; -} - -static void pclose(struct atm_vcc *vcc) -{ - struct solos_card *card = vcc->dev->dev_data; - unsigned char port = SOLOS_CHAN(vcc->dev); - struct sk_buff *skb, *tmpskb; - struct pkt_hdr *header; - - /* Remove any yet-to-be-transmitted packets from the pending queue */ - spin_lock_bh(&card->tx_queue_lock); - skb_queue_walk_safe(&card->tx_queue[port], skb, tmpskb) { - if (SKB_CB(skb)->vcc == vcc) { - skb_unlink(skb, &card->tx_queue[port]); - solos_pop(vcc, skb); - } - } - spin_unlock_bh(&card->tx_queue_lock); - - skb = alloc_skb(sizeof(*header), GFP_KERNEL); - if (!skb) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); - return; - } - header = skb_put(skb, sizeof(*header)); - - header->size = cpu_to_le16(0); - header->vpi = cpu_to_le16(vcc->vpi); - header->vci = cpu_to_le16(vcc->vci); - header->type = cpu_to_le16(PKT_PCLOSE); - - skb_get(skb); - fpga_queue(card, port, skb, NULL); - - if (!wait_event_timeout(card->param_wq, !skb_shared(skb), 5 * HZ)) - dev_warn(&card->dev->dev, - "Timeout waiting for VCC close on port %d\n", port); - - dev_kfree_skb(skb); - - /* Hold up vcc_destroy_socket() (our caller) until solos_bh() in the - tasklet has finished processing any incoming packets (and, more to - the point, using the vcc pointer). */ - tasklet_unlock_wait(&card->tlet); - - clear_bit(ATM_VF_ADDR, &vcc->flags); - - return; -} - -static int print_buffer(struct sk_buff *buf) -{ - int len,i; - char msg[500]; - char item[10]; - - len = buf->len; - for (i = 0; i < len; i++){ - if(i % 8 == 0) - sprintf(msg, "%02X: ", i); - - sprintf(item,"%02X ",*(buf->data + i)); - strcat(msg, item); - if(i % 8 == 7) { - sprintf(item, "\n"); - strcat(msg, item); - printk(KERN_DEBUG "%s", msg); - } - } - if (i % 8 != 0) { - sprintf(item, "\n"); - strcat(msg, item); - printk(KERN_DEBUG "%s", msg); - } - printk(KERN_DEBUG "\n"); - - return 0; -} - -static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, - struct atm_vcc *vcc) -{ - int old_len; - unsigned long flags; - - SKB_CB(skb)->vcc = vcc; - - spin_lock_irqsave(&card->tx_queue_lock, flags); - old_len = skb_queue_len(&card->tx_queue[port]); - skb_queue_tail(&card->tx_queue[port], skb); - if (!old_len) - card->tx_mask |= (1 << port); - spin_unlock_irqrestore(&card->tx_queue_lock, flags); - - /* Theoretically we could just schedule the tasklet here, but - that introduces latency we don't want -- it's noticeable */ - if (!old_len) - fpga_tx(card); -} - -static uint32_t fpga_tx(struct solos_card *card) -{ - uint32_t tx_pending, card_flags; - uint32_t tx_started = 0; - struct sk_buff *skb; - struct atm_vcc *vcc; - unsigned char port; - unsigned long flags; - - spin_lock_irqsave(&card->tx_lock, flags); - - card_flags = ioread32(card->config_regs + FLAGS_ADDR); - /* - * The queue lock is required for _writing_ to tx_mask, but we're - * OK to read it here without locking. The only potential update - * that we could race with is in fpga_queue() where it sets a bit - * for a new port... but it's going to call this function again if - * it's doing that, anyway. - */ - tx_pending = card->tx_mask & ~card_flags; - - for (port = 0; tx_pending; tx_pending >>= 1, port++) { - if (tx_pending & 1) { - struct sk_buff *oldskb = card->tx_skb[port]; - if (oldskb) { - dma_unmap_single(&card->dev->dev, SKB_CB(oldskb)->dma_addr, - oldskb->len, DMA_TO_DEVICE); - card->tx_skb[port] = NULL; - } - spin_lock(&card->tx_queue_lock); - skb = skb_dequeue(&card->tx_queue[port]); - if (!skb) - card->tx_mask &= ~(1 << port); - spin_unlock(&card->tx_queue_lock); - - if (skb && !card->using_dma) { - memcpy_toio(TX_BUF(card, port), skb->data, skb->len); - tx_started |= 1 << port; - oldskb = skb; /* We're done with this skb already */ - } else if (skb && card->using_dma) { - unsigned char *data = skb->data; - if ((unsigned long)data & card->dma_alignment) { - data = card->dma_bounce + (BUF_SIZE * port); - memcpy(data, skb->data, skb->len); - } - SKB_CB(skb)->dma_addr = dma_map_single(&card->dev->dev, data, - skb->len, DMA_TO_DEVICE); - card->tx_skb[port] = skb; - iowrite32(SKB_CB(skb)->dma_addr, - card->config_regs + TX_DMA_ADDR(port)); - } - - if (!oldskb) - continue; - - /* Clean up and free oldskb now it's gone */ - if (atmdebug) { - struct pkt_hdr *header = (void *)oldskb->data; - int size = le16_to_cpu(header->size); - - skb_pull(oldskb, sizeof(*header)); - dev_info(&card->dev->dev, "Transmitted: port %d\n", - port); - dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", - size, le16_to_cpu(header->vpi), - le16_to_cpu(header->vci)); - print_buffer(oldskb); - } - - vcc = SKB_CB(oldskb)->vcc; - - if (vcc) { - atomic_inc(&vcc->stats->tx); - solos_pop(vcc, oldskb); - } else { - dev_kfree_skb_irq(oldskb); - wake_up(&card->param_wq); - } - } - } - /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */ - if (tx_started) - iowrite32(tx_started, card->config_regs + FLAGS_ADDR); - - spin_unlock_irqrestore(&card->tx_lock, flags); - return card_flags; -} - -static int psend(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct solos_card *card = vcc->dev->dev_data; - struct pkt_hdr *header; - int pktlen; - - pktlen = skb->len; - if (pktlen > (BUF_SIZE - sizeof(*header))) { - dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); - solos_pop(vcc, skb); - return 0; - } - - if (!skb_clone_writable(skb, sizeof(*header))) { - int expand_by = 0; - int ret; - - if (skb_headroom(skb) < sizeof(*header)) - expand_by = sizeof(*header) - skb_headroom(skb); - - ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); - if (ret) { - dev_warn(&card->dev->dev, "pskb_expand_head failed.\n"); - solos_pop(vcc, skb); - return ret; - } - } - - header = skb_push(skb, sizeof(*header)); - - /* This does _not_ include the size of the header */ - header->size = cpu_to_le16(pktlen); - header->vpi = cpu_to_le16(vcc->vpi); - header->vci = cpu_to_le16(vcc->vci); - header->type = cpu_to_le16(PKT_DATA); - - fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, vcc); - - return 0; -} - -static const struct atmdev_ops fpga_ops = { - .open = popen, - .close = pclose, - .ioctl = NULL, - .send = psend, - .send_oam = NULL, - .phy_put = NULL, - .phy_get = NULL, - .change_qos = NULL, - .proc_read = NULL, - .owner = THIS_MODULE -}; - -static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int err; - uint16_t fpga_ver; - uint8_t major_ver, minor_ver; - uint32_t data32; - struct solos_card *card; - - card = kzalloc_obj(*card); - if (!card) - return -ENOMEM; - - card->dev = dev; - init_waitqueue_head(&card->fw_wq); - init_waitqueue_head(&card->param_wq); - - err = pci_enable_device(dev); - if (err) { - dev_warn(&dev->dev, "Failed to enable PCI device\n"); - goto out; - } - - err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); - if (err) { - dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n"); - goto out; - } - - err = pci_request_regions(dev, "solos"); - if (err) { - dev_warn(&dev->dev, "Failed to request regions\n"); - goto out; - } - - card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); - if (!card->config_regs) { - dev_warn(&dev->dev, "Failed to ioremap config registers\n"); - err = -ENOMEM; - goto out_release_regions; - } - card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); - if (!card->buffers) { - dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); - err = -ENOMEM; - goto out_unmap_config; - } - - if (reset) { - iowrite32(1, card->config_regs + FPGA_MODE); - ioread32(card->config_regs + FPGA_MODE); - - iowrite32(0, card->config_regs + FPGA_MODE); - ioread32(card->config_regs + FPGA_MODE); - } - - data32 = ioread32(card->config_regs + FPGA_VER); - fpga_ver = (data32 & 0x0000FFFF); - major_ver = ((data32 & 0xFF000000) >> 24); - minor_ver = ((data32 & 0x00FF0000) >> 16); - card->fpga_version = FPGA_VERSION(major_ver,minor_ver); - if (card->fpga_version > LEGACY_BUFFERS) - card->buffer_size = BUF_SIZE; - else - card->buffer_size = OLD_BUF_SIZE; - dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", - major_ver, minor_ver, fpga_ver); - - if (fpga_ver < 37 && (fpga_upgrade || firmware_upgrade || - db_fpga_upgrade || db_firmware_upgrade)) { - dev_warn(&dev->dev, - "FPGA too old; cannot upgrade flash. Use JTAG.\n"); - fpga_upgrade = firmware_upgrade = 0; - db_fpga_upgrade = db_firmware_upgrade = 0; - } - - /* Stopped using Atmel flash after 0.03-38 */ - if (fpga_ver < 39) - card->atmel_flash = 1; - else - card->atmel_flash = 0; - - data32 = ioread32(card->config_regs + PORTS); - card->nr_ports = (data32 & 0x000000FF); - - if (card->fpga_version >= DMA_SUPPORTED) { - pci_set_master(dev); - card->using_dma = 1; - if (1) { /* All known FPGA versions so far */ - card->dma_alignment = 3; - card->dma_bounce = kmalloc_array(card->nr_ports, - BUF_SIZE, GFP_KERNEL); - if (!card->dma_bounce) { - dev_warn(&card->dev->dev, "Failed to allocate DMA bounce buffers\n"); - err = -ENOMEM; - /* Fallback to MMIO doesn't work */ - goto out_unmap_both; - } - } - } else { - card->using_dma = 0; - /* Set RX empty flag for all ports */ - iowrite32(0xF0, card->config_regs + FLAGS_ADDR); - } - - pci_set_drvdata(dev, card); - - tasklet_init(&card->tlet, solos_bh, (unsigned long)card); - spin_lock_init(&card->tx_lock); - spin_lock_init(&card->tx_queue_lock); - spin_lock_init(&card->cli_queue_lock); - spin_lock_init(&card->param_queue_lock); - INIT_LIST_HEAD(&card->param_queue); - - err = request_irq(dev->irq, solos_irq, IRQF_SHARED, - "solos-pci", card); - if (err) { - dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); - goto out_unmap_both; - } - - iowrite32(1, card->config_regs + IRQ_EN_ADDR); - - if (fpga_upgrade) - flash_upgrade(card, 0); - - if (firmware_upgrade) - flash_upgrade(card, 1); - - if (db_fpga_upgrade) - flash_upgrade(card, 2); - - if (db_firmware_upgrade) - flash_upgrade(card, 3); - - err = atm_init(card, &dev->dev); - if (err) - goto out_free_irq; - - if (card->fpga_version >= DMA_SUPPORTED && - sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group)) - dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n"); - - return 0; - - out_free_irq: - iowrite32(0, card->config_regs + IRQ_EN_ADDR); - free_irq(dev->irq, card); - tasklet_kill(&card->tlet); - - out_unmap_both: - kfree(card->dma_bounce); - pci_iounmap(dev, card->buffers); - out_unmap_config: - pci_iounmap(dev, card->config_regs); - out_release_regions: - pci_release_regions(dev); - out: - kfree(card); - return err; -} - -static int atm_init(struct solos_card *card, struct device *parent) -{ - int i; - - for (i = 0; i < card->nr_ports; i++) { - struct sk_buff *skb; - struct pkt_hdr *header; - - skb_queue_head_init(&card->tx_queue[i]); - skb_queue_head_init(&card->cli_queue[i]); - - card->atmdev[i] = atm_dev_register("solos-pci", parent, &fpga_ops, -1, NULL); - if (!card->atmdev[i]) { - dev_err(&card->dev->dev, "Could not register ATM device %d\n", i); - atm_remove(card); - return -ENODEV; - } - if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) - dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); - if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group)) - dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i); - - dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); - - card->atmdev[i]->ci_range.vpi_bits = 8; - card->atmdev[i]->ci_range.vci_bits = 16; - card->atmdev[i]->dev_data = card; - card->atmdev[i]->phy_data = (void *)(unsigned long)i; - atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); - - skb = alloc_skb(sizeof(*header), GFP_KERNEL); - if (!skb) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); - continue; - } - - header = skb_put(skb, sizeof(*header)); - - header->size = cpu_to_le16(0); - header->vpi = cpu_to_le16(0); - header->vci = cpu_to_le16(0); - header->type = cpu_to_le16(PKT_STATUS); - - fpga_queue(card, i, skb, NULL); - } - return 0; -} - -static void atm_remove(struct solos_card *card) -{ - int i; - - for (i = 0; i < card->nr_ports; i++) { - if (card->atmdev[i]) { - struct sk_buff *skb; - - dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); - - sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group); - atm_dev_deregister(card->atmdev[i]); - - skb = card->rx_skb[i]; - if (skb) { - dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, - RX_DMA_SIZE, DMA_FROM_DEVICE); - dev_kfree_skb(skb); - } - skb = card->tx_skb[i]; - if (skb) { - dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr, - skb->len, DMA_TO_DEVICE); - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&card->tx_queue[i]))) - dev_kfree_skb(skb); - - } - } -} - -static void fpga_remove(struct pci_dev *dev) -{ - struct solos_card *card = pci_get_drvdata(dev); - - /* Disable IRQs */ - iowrite32(0, card->config_regs + IRQ_EN_ADDR); - - /* Reset FPGA */ - iowrite32(1, card->config_regs + FPGA_MODE); - (void)ioread32(card->config_regs + FPGA_MODE); - - if (card->fpga_version >= DMA_SUPPORTED) - sysfs_remove_group(&card->dev->dev.kobj, &gpio_attr_group); - - atm_remove(card); - - free_irq(dev->irq, card); - tasklet_kill(&card->tlet); - - kfree(card->dma_bounce); - - /* Release device from reset */ - iowrite32(0, card->config_regs + FPGA_MODE); - (void)ioread32(card->config_regs + FPGA_MODE); - - pci_iounmap(dev, card->buffers); - pci_iounmap(dev, card->config_regs); - - pci_release_regions(dev); - pci_disable_device(dev); - - kfree(card); -} - -static const struct pci_device_id fpga_pci_tbl[] = { - { 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci,fpga_pci_tbl); - -static struct pci_driver fpga_driver = { - .name = "solos", - .id_table = fpga_pci_tbl, - .probe = fpga_probe, - .remove = fpga_remove, -}; - - -static int __init solos_pci_init(void) -{ - BUILD_BUG_ON(sizeof(struct solos_skb_cb) > sizeof(((struct sk_buff *)0)->cb)); - - printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); - return pci_register_driver(&fpga_driver); -} - -static void __exit solos_pci_exit(void) -{ - pci_unregister_driver(&fpga_driver); - printk(KERN_INFO "Solos PCI Driver %s Unloaded\n", VERSION); -} - -module_init(solos_pci_init); -module_exit(solos_pci_exit); diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c deleted file mode 100644 index bb588c98216d..000000000000 --- a/drivers/atm/suni.c +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/atm/suni.c - S/UNI PHY driver - * - * Supports the following: - * PMC PM5346 S/UNI LITE - * PMC PM5350 S/UNI 155 ULTRA - * PMC PM5355 S/UNI 622 - */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "suni.h" - - -#if 0 -#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) -#else -#define DPRINTK(format,args...) -#endif - -#define PRIV(dev) ((struct suni_priv *) dev->phy_data) - -#define PUT(val,reg) dev->ops->phy_put(dev,val,SUNI_##reg) -#define GET(reg) dev->ops->phy_get(dev,SUNI_##reg) -#define REG_CHANGE(mask,shift,value,reg) \ - PUT((GET(reg) & ~(mask)) | ((value) << (shift)),reg) - - -static struct timer_list poll_timer; -static struct suni_priv *sunis = NULL; -static DEFINE_SPINLOCK(sunis_lock); - - -#define ADD_LIMITED(s,v) \ - atomic_add((v),&stats->s); \ - if (atomic_read(&stats->s) < 0) atomic_set(&stats->s,INT_MAX); - - -static void suni_hz(struct timer_list *timer) -{ - struct suni_priv *walk; - struct atm_dev *dev; - struct k_sonet_stats *stats; - - for (walk = sunis; walk; walk = walk->next) { - dev = walk->dev; - stats = &walk->sonet_stats; - PUT(0,MRI); /* latch counters */ - udelay(1); - ADD_LIMITED(section_bip,(GET(RSOP_SBL) & 0xff) | - ((GET(RSOP_SBM) & 0xff) << 8)); - ADD_LIMITED(line_bip,(GET(RLOP_LBL) & 0xff) | - ((GET(RLOP_LB) & 0xff) << 8) | - ((GET(RLOP_LBM) & 0xf) << 16)); - ADD_LIMITED(path_bip,(GET(RPOP_PBL) & 0xff) | - ((GET(RPOP_PBM) & 0xff) << 8)); - ADD_LIMITED(line_febe,(GET(RLOP_LFL) & 0xff) | - ((GET(RLOP_LF) & 0xff) << 8) | - ((GET(RLOP_LFM) & 0xf) << 16)); - ADD_LIMITED(path_febe,(GET(RPOP_PFL) & 0xff) | - ((GET(RPOP_PFM) & 0xff) << 8)); - ADD_LIMITED(corr_hcs,GET(RACP_CHEC) & 0xff); - ADD_LIMITED(uncorr_hcs,GET(RACP_UHEC) & 0xff); - ADD_LIMITED(rx_cells,(GET(RACP_RCCL) & 0xff) | - ((GET(RACP_RCC) & 0xff) << 8) | - ((GET(RACP_RCCM) & 7) << 16)); - ADD_LIMITED(tx_cells,(GET(TACP_TCCL) & 0xff) | - ((GET(TACP_TCC) & 0xff) << 8) | - ((GET(TACP_TCCM) & 7) << 16)); - } - if (timer) mod_timer(&poll_timer,jiffies+HZ); -} - - -#undef ADD_LIMITED - - -static int fetch_stats(struct atm_dev *dev,struct sonet_stats __user *arg,int zero) -{ - struct sonet_stats tmp; - int error = 0; - - sonet_copy_stats(&PRIV(dev)->sonet_stats,&tmp); - if (arg) error = copy_to_user(arg,&tmp,sizeof(tmp)); - if (zero && !error) sonet_subtract_stats(&PRIV(dev)->sonet_stats,&tmp); - return error ? -EFAULT : 0; -} - - -#define HANDLE_FLAG(flag,reg,bit) \ - if (todo & flag) { \ - if (set) PUT(GET(reg) | bit,reg); \ - else PUT(GET(reg) & ~bit,reg); \ - todo &= ~flag; \ - } - - -static int change_diag(struct atm_dev *dev,void __user *arg,int set) -{ - int todo; - - if (get_user(todo,(int __user *)arg)) return -EFAULT; - HANDLE_FLAG(SONET_INS_SBIP,TSOP_DIAG,SUNI_TSOP_DIAG_DBIP8); - HANDLE_FLAG(SONET_INS_LBIP,TLOP_DIAG,SUNI_TLOP_DIAG_DBIP); - HANDLE_FLAG(SONET_INS_PBIP,TPOP_CD,SUNI_TPOP_DIAG_DB3); - HANDLE_FLAG(SONET_INS_FRAME,RSOP_CIE,SUNI_RSOP_CIE_FOOF); - HANDLE_FLAG(SONET_INS_LAIS,TSOP_CTRL,SUNI_TSOP_CTRL_LAIS); - HANDLE_FLAG(SONET_INS_PAIS,TPOP_CD,SUNI_TPOP_DIAG_PAIS); - HANDLE_FLAG(SONET_INS_LOS,TSOP_DIAG,SUNI_TSOP_DIAG_DLOS); - HANDLE_FLAG(SONET_INS_HCS,TACP_CS,SUNI_TACP_CS_DHCS); - return put_user(todo,(int __user *)arg) ? -EFAULT : 0; -} - - -#undef HANDLE_FLAG - - -static int get_diag(struct atm_dev *dev,void __user *arg) -{ - int set; - - set = 0; - if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DBIP8) set |= SONET_INS_SBIP; - if (GET(TLOP_DIAG) & SUNI_TLOP_DIAG_DBIP) set |= SONET_INS_LBIP; - if (GET(TPOP_CD) & SUNI_TPOP_DIAG_DB3) set |= SONET_INS_PBIP; - /* SONET_INS_FRAME is one-shot only */ - if (GET(TSOP_CTRL) & SUNI_TSOP_CTRL_LAIS) set |= SONET_INS_LAIS; - if (GET(TPOP_CD) & SUNI_TPOP_DIAG_PAIS) set |= SONET_INS_PAIS; - if (GET(TSOP_DIAG) & SUNI_TSOP_DIAG_DLOS) set |= SONET_INS_LOS; - if (GET(TACP_CS) & SUNI_TACP_CS_DHCS) set |= SONET_INS_HCS; - return put_user(set,(int __user *)arg) ? -EFAULT : 0; -} - - -static int set_loopback(struct atm_dev *dev,int mode) -{ - unsigned char control; - int reg, dle, lle; - - if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { - reg = SUNI_MCM; - dle = SUNI_MCM_DLE; - lle = SUNI_MCM_LLE; - } else { - reg = SUNI_MCT; - dle = SUNI_MCT_DLE; - lle = SUNI_MCT_LLE; - } - - control = dev->ops->phy_get(dev, reg) & ~(dle | lle); - switch (mode) { - case ATM_LM_NONE: - break; - case ATM_LM_LOC_PHY: - control |= dle; - break; - case ATM_LM_RMT_PHY: - control |= lle; - break; - default: - return -EINVAL; - } - dev->ops->phy_put(dev, control, reg); - PRIV(dev)->loop_mode = mode; - return 0; -} - -/* - * SONET vs. SDH Configuration - * - * Z0INS (register 0x06): 0 for SONET, 1 for SDH - * ENSS (register 0x3D): 0 for SONET, 1 for SDH - * LEN16 (register 0x28): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) - * LEN16 (register 0x50): 0 for SONET, 1 for SDH (n/a for S/UNI 155 QUAD) - * S[1:0] (register 0x46): 00 for SONET, 10 for SDH - */ - -static int set_sonet(struct atm_dev *dev) -{ - if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { - PUT(GET(RPOP_RC) & ~SUNI_RPOP_RC_ENSS, RPOP_RC); - PUT(GET(SSTB_CTRL) & ~SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); - PUT(GET(SPTB_CTRL) & ~SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); - } - - REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, - SUNI_TPOP_S_SONET, TPOP_APM); - - return 0; -} - -static int set_sdh(struct atm_dev *dev) -{ - if (PRIV(dev)->type == SUNI_MRI_TYPE_PM5355) { - PUT(GET(RPOP_RC) | SUNI_RPOP_RC_ENSS, RPOP_RC); - PUT(GET(SSTB_CTRL) | SUNI_SSTB_CTRL_LEN16, SSTB_CTRL); - PUT(GET(SPTB_CTRL) | SUNI_SPTB_CTRL_LEN16, SPTB_CTRL); - } - - REG_CHANGE(SUNI_TPOP_APM_S, SUNI_TPOP_APM_S_SHIFT, - SUNI_TPOP_S_SDH, TPOP_APM); - - return 0; -} - - -static int get_framing(struct atm_dev *dev, void __user *arg) -{ - int framing; - unsigned char s; - - - s = (GET(TPOP_APM) & SUNI_TPOP_APM_S) >> SUNI_TPOP_APM_S_SHIFT; - if (s == SUNI_TPOP_S_SONET) - framing = SONET_FRAME_SONET; - else - framing = SONET_FRAME_SDH; - - return put_user(framing, (int __user *) arg) ? -EFAULT : 0; -} - -static int set_framing(struct atm_dev *dev, void __user *arg) -{ - int mode; - - if (get_user(mode, (int __user *) arg)) - return -EFAULT; - - if (mode == SONET_FRAME_SONET) - return set_sonet(dev); - else if (mode == SONET_FRAME_SDH) - return set_sdh(dev); - - return -EINVAL; -} - - -static int suni_ioctl(struct atm_dev *dev,unsigned int cmd,void __user *arg) -{ - switch (cmd) { - case SONET_GETSTATZ: - case SONET_GETSTAT: - return fetch_stats(dev, arg, cmd == SONET_GETSTATZ); - case SONET_SETDIAG: - return change_diag(dev,arg,1); - case SONET_CLRDIAG: - return change_diag(dev,arg,0); - case SONET_GETDIAG: - return get_diag(dev,arg); - case SONET_SETFRAMING: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return set_framing(dev, arg); - case SONET_GETFRAMING: - return get_framing(dev, arg); - case SONET_GETFRSENSE: - return -EINVAL; - case ATM_SETLOOP: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - return set_loopback(dev,(int)(unsigned long)arg); - case ATM_GETLOOP: - return put_user(PRIV(dev)->loop_mode,(int __user *)arg) ? - -EFAULT : 0; - case ATM_QUERYLOOP: - return put_user(ATM_LM_LOC_PHY | ATM_LM_RMT_PHY, - (int __user *) arg) ? -EFAULT : 0; - default: - return -ENOIOCTLCMD; - } -} - - -static void poll_los(struct atm_dev *dev) -{ - atm_dev_signal_change(dev, - GET(RSOP_SIS) & SUNI_RSOP_SIS_LOSV ? - ATM_PHY_SIG_LOST : ATM_PHY_SIG_FOUND); -} - - -static void suni_int(struct atm_dev *dev) -{ - poll_los(dev); - printk(KERN_NOTICE "%s(itf %d): signal %s\n",dev->type,dev->number, - dev->signal == ATM_PHY_SIG_LOST ? "lost" : "detected again"); -} - - -static int suni_start(struct atm_dev *dev) -{ - unsigned long flags; - int first; - - spin_lock_irqsave(&sunis_lock,flags); - first = !sunis; - PRIV(dev)->next = sunis; - sunis = PRIV(dev); - spin_unlock_irqrestore(&sunis_lock,flags); - memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats)); - PUT(GET(RSOP_CIE) | SUNI_RSOP_CIE_LOSE,RSOP_CIE); - /* interrupt on loss of signal */ - poll_los(dev); /* ... and clear SUNI interrupts */ - if (dev->signal == ATM_PHY_SIG_LOST) - printk(KERN_WARNING "%s(itf %d): no signal\n",dev->type, - dev->number); - PRIV(dev)->loop_mode = ATM_LM_NONE; - suni_hz(NULL); /* clear SUNI counters */ - (void) fetch_stats(dev,NULL,1); /* clear kernel counters */ - if (first) { - timer_setup(&poll_timer, suni_hz, 0); - poll_timer.expires = jiffies+HZ; -#if 0 -printk(KERN_DEBUG "[u] p=0x%lx,n=0x%lx\n",(unsigned long) poll_timer.list.prev, - (unsigned long) poll_timer.list.next); -#endif - add_timer(&poll_timer); - } - return 0; -} - - -static int suni_stop(struct atm_dev *dev) -{ - struct suni_priv **walk; - unsigned long flags; - - /* let SAR driver worry about stopping interrupts */ - spin_lock_irqsave(&sunis_lock,flags); - for (walk = &sunis; *walk != PRIV(dev); - walk = &PRIV((*walk)->dev)->next); - *walk = PRIV((*walk)->dev)->next; - if (!sunis) timer_delete_sync(&poll_timer); - spin_unlock_irqrestore(&sunis_lock,flags); - kfree(PRIV(dev)); - - return 0; -} - - -static const struct atmphy_ops suni_ops = { - .start = suni_start, - .ioctl = suni_ioctl, - .interrupt = suni_int, - .stop = suni_stop, -}; - - -int suni_init(struct atm_dev *dev) -{ - unsigned char mri; - - if (!(dev->phy_data = kmalloc_obj(struct suni_priv))) - return -ENOMEM; - PRIV(dev)->dev = dev; - - mri = GET(MRI); /* reset SUNI */ - PRIV(dev)->type = (mri & SUNI_MRI_TYPE) >> SUNI_MRI_TYPE_SHIFT; - PUT(mri | SUNI_MRI_RESET,MRI); - PUT(mri,MRI); - PUT((GET(MT) & SUNI_MT_DS27_53),MT); /* disable all tests */ - set_sonet(dev); - REG_CHANGE(SUNI_TACP_IUCHP_CLP,0,SUNI_TACP_IUCHP_CLP, - TACP_IUCHP); /* idle cells */ - PUT(SUNI_IDLE_PATTERN,TACP_IUCPOP); - dev->phy = &suni_ops; - - return 0; -} - -EXPORT_SYMBOL(suni_init); - -MODULE_DESCRIPTION("S/UNI PHY driver"); -MODULE_LICENSE("GPL"); diff --git a/net/atm/br2684.c b/net/atm/br2684.c deleted file mode 100644 index 6580d67c3456..000000000000 --- a/net/atm/br2684.c +++ /dev/null @@ -1,872 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ethernet netdevice using ATM AAL5 as underlying carrier - * (RFC1483 obsoleted by RFC2684) for Linux - * - * Authors: Marcell GAL, 2000, XDSL Ltd, Hungary - * Eric Kinzie, 2006-2007, US Naval Research Laboratory - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "common.h" - -static void skb_debug(const struct sk_buff *skb) -{ -#ifdef SKB_DEBUG -#define NUM2PRINT 50 - print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET, - 16, 1, skb->data, min(NUM2PRINT, skb->len), true); -#endif -} - -#define BR2684_ETHERTYPE_LEN 2 -#define BR2684_PAD_LEN 2 - -#define LLC 0xaa, 0xaa, 0x03 -#define SNAP_BRIDGED 0x00, 0x80, 0xc2 -#define SNAP_ROUTED 0x00, 0x00, 0x00 -#define PID_ETHERNET 0x00, 0x07 -#define ETHERTYPE_IPV4 0x08, 0x00 -#define ETHERTYPE_IPV6 0x86, 0xdd -#define PAD_BRIDGED 0x00, 0x00 - -static const unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 }; -static const unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 }; -static const unsigned char llc_oui_pid_pad[] = - { LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED }; -static const unsigned char pad[] = { PAD_BRIDGED }; -static const unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 }; -static const unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 }; - -enum br2684_encaps { - e_vc = BR2684_ENCAPS_VC, - e_llc = BR2684_ENCAPS_LLC, -}; - -struct br2684_vcc { - struct atm_vcc *atmvcc; - struct net_device *device; - /* keep old push, pop functions for chaining */ - void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); - void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); - void (*old_release_cb)(struct atm_vcc *vcc); - struct module *old_owner; - enum br2684_encaps encaps; - struct list_head brvccs; -#ifdef CONFIG_ATM_BR2684_IPFILTER - struct br2684_filter filter; -#endif /* CONFIG_ATM_BR2684_IPFILTER */ - unsigned int copies_needed, copies_failed; - atomic_t qspace; -}; - -struct br2684_dev { - struct net_device *net_dev; - struct list_head br2684_devs; - int number; - struct list_head brvccs; /* one device <=> one vcc (before xmas) */ - int mac_was_set; - enum br2684_payload payload; -}; - -/* - * This lock should be held for writing any time the list of devices or - * their attached vcc's could be altered. It should be held for reading - * any time these are being queried. Note that we sometimes need to - * do read-locking under interrupting context, so write locking must block - * the current CPU's interrupts. - */ -static DEFINE_RWLOCK(devs_lock); - -static LIST_HEAD(br2684_devs); - -static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) -{ - return netdev_priv(net_dev); -} - -static inline struct net_device *list_entry_brdev(const struct list_head *le) -{ - return list_entry(le, struct br2684_dev, br2684_devs)->net_dev; -} - -static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc) -{ - return (struct br2684_vcc *)(atmvcc->user_back); -} - -static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le) -{ - return list_entry(le, struct br2684_vcc, brvccs); -} - -/* Caller should hold read_lock(&devs_lock) */ -static struct net_device *br2684_find_dev(const struct br2684_if_spec *s) -{ - struct list_head *lh; - struct net_device *net_dev; - switch (s->method) { - case BR2684_FIND_BYNUM: - list_for_each(lh, &br2684_devs) { - net_dev = list_entry_brdev(lh); - if (BRPRIV(net_dev)->number == s->spec.devnum) - return net_dev; - } - break; - case BR2684_FIND_BYIFNAME: - list_for_each(lh, &br2684_devs) { - net_dev = list_entry_brdev(lh); - if (!strncmp(net_dev->name, s->spec.ifname, IFNAMSIZ)) - return net_dev; - } - break; - } - return NULL; -} - -static int atm_dev_event(struct notifier_block *this, unsigned long event, - void *arg) -{ - struct atm_dev *atm_dev = arg; - struct list_head *lh; - struct net_device *net_dev; - struct br2684_vcc *brvcc; - struct atm_vcc *atm_vcc; - unsigned long flags; - - pr_debug("event=%ld dev=%p\n", event, atm_dev); - - read_lock_irqsave(&devs_lock, flags); - list_for_each(lh, &br2684_devs) { - net_dev = list_entry_brdev(lh); - - list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) { - atm_vcc = brvcc->atmvcc; - if (atm_vcc && brvcc->atmvcc->dev == atm_dev) { - - if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST) - netif_carrier_off(net_dev); - else - netif_carrier_on(net_dev); - - } - } - } - read_unlock_irqrestore(&devs_lock, flags); - - return NOTIFY_DONE; -} - -static struct notifier_block atm_dev_notifier = { - .notifier_call = atm_dev_event, -}; - -/* chained vcc->pop function. Check if we should wake the netif_queue */ -static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct br2684_vcc *brvcc = BR2684_VCC(vcc); - - pr_debug("(vcc %p ; net_dev %p )\n", vcc, brvcc->device); - brvcc->old_pop(vcc, skb); - - /* If the queue space just went up from zero, wake */ - if (atomic_inc_return(&brvcc->qspace) == 1) - netif_wake_queue(brvcc->device); -} - -/* - * Send a packet out a particular vcc. Not to useful right now, but paves - * the way for multiple vcc's per itf. Returns true if we can send, - * otherwise false - */ -static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev, - struct br2684_vcc *brvcc) -{ - struct br2684_dev *brdev = BRPRIV(dev); - struct atm_vcc *atmvcc; - int minheadroom = (brvcc->encaps == e_llc) ? - ((brdev->payload == p_bridged) ? - sizeof(llc_oui_pid_pad) : sizeof(llc_oui_ipv4)) : - ((brdev->payload == p_bridged) ? BR2684_PAD_LEN : 0); - - if (skb_headroom(skb) < minheadroom) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); - brvcc->copies_needed++; - dev_kfree_skb(skb); - if (skb2 == NULL) { - brvcc->copies_failed++; - return 0; - } - skb = skb2; - } - - if (brvcc->encaps == e_llc) { - if (brdev->payload == p_bridged) { - skb_push(skb, sizeof(llc_oui_pid_pad)); - skb_copy_to_linear_data(skb, llc_oui_pid_pad, - sizeof(llc_oui_pid_pad)); - } else if (brdev->payload == p_routed) { - unsigned short prot = ntohs(skb->protocol); - - skb_push(skb, sizeof(llc_oui_ipv4)); - switch (prot) { - case ETH_P_IP: - skb_copy_to_linear_data(skb, llc_oui_ipv4, - sizeof(llc_oui_ipv4)); - break; - case ETH_P_IPV6: - skb_copy_to_linear_data(skb, llc_oui_ipv6, - sizeof(llc_oui_ipv6)); - break; - default: - dev_kfree_skb(skb); - return 0; - } - } - } else { /* e_vc */ - if (brdev->payload == p_bridged) { - skb_push(skb, 2); - memset(skb->data, 0, 2); - } - } - skb_debug(skb); - - ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc; - pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev); - atm_account_tx(atmvcc, skb); - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - if (atomic_dec_return(&brvcc->qspace) < 1) { - /* No more please! */ - netif_stop_queue(brvcc->device); - /* We might have raced with br2684_pop() */ - if (unlikely(atomic_read(&brvcc->qspace) > 0)) - netif_wake_queue(brvcc->device); - } - - /* If this fails immediately, the skb will be freed and br2684_pop() - will wake the queue if appropriate. Just return an error so that - the stats are updated correctly */ - return !atmvcc->send(atmvcc, skb); -} - -static void br2684_release_cb(struct atm_vcc *atmvcc) -{ - struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); - - if (atomic_read(&brvcc->qspace) > 0) - netif_wake_queue(brvcc->device); - - if (brvcc->old_release_cb) - brvcc->old_release_cb(atmvcc); -} - -static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, - const struct br2684_dev *brdev) -{ - return list_empty(&brdev->brvccs) ? NULL : list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */ -} - -static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct br2684_dev *brdev = BRPRIV(dev); - struct br2684_vcc *brvcc; - struct atm_vcc *atmvcc; - netdev_tx_t ret = NETDEV_TX_OK; - - pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); - read_lock(&devs_lock); - brvcc = pick_outgoing_vcc(skb, brdev); - if (brvcc == NULL) { - pr_debug("no vcc attached to dev %s\n", dev->name); - dev->stats.tx_errors++; - dev->stats.tx_carrier_errors++; - /* netif_stop_queue(dev); */ - dev_kfree_skb(skb); - goto out_devs; - } - atmvcc = brvcc->atmvcc; - - bh_lock_sock(sk_atm(atmvcc)); - - if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) || - test_bit(ATM_VF_CLOSE, &atmvcc->flags) || - !test_bit(ATM_VF_READY, &atmvcc->flags)) { - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - goto out; - } - - if (sock_owned_by_user(sk_atm(atmvcc))) { - netif_stop_queue(brvcc->device); - ret = NETDEV_TX_BUSY; - goto out; - } - - if (!br2684_xmit_vcc(skb, dev, brvcc)) { - /* - * We should probably use netif_*_queue() here, but that - * involves added complication. We need to walk before - * we can run. - * - * Don't free here! this pointer might be no longer valid! - */ - dev->stats.tx_errors++; - dev->stats.tx_fifo_errors++; - } - out: - bh_unlock_sock(sk_atm(atmvcc)); - out_devs: - read_unlock(&devs_lock); - return ret; -} - -/* - * We remember when the MAC gets set, so we don't override it later with - * the ESI of the ATM card of the first VC - */ -static int br2684_mac_addr(struct net_device *dev, void *p) -{ - int err = eth_mac_addr(dev, p); - if (!err) - BRPRIV(dev)->mac_was_set = 1; - return err; -} - -#ifdef CONFIG_ATM_BR2684_IPFILTER -/* this IOCTL is experimental. */ -static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg) -{ - struct br2684_vcc *brvcc; - struct br2684_filter_set fs; - - if (copy_from_user(&fs, arg, sizeof fs)) - return -EFAULT; - if (fs.ifspec.method != BR2684_FIND_BYNOTHING) { - /* - * This is really a per-vcc thing, but we can also search - * by device. - */ - struct br2684_dev *brdev; - read_lock(&devs_lock); - brdev = BRPRIV(br2684_find_dev(&fs.ifspec)); - if (brdev == NULL || list_empty(&brdev->brvccs) || - brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ - brvcc = NULL; - else - brvcc = list_entry_brvcc(brdev->brvccs.next); - read_unlock(&devs_lock); - if (brvcc == NULL) - return -ESRCH; - } else - brvcc = BR2684_VCC(atmvcc); - memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter)); - return 0; -} - -/* Returns 1 if packet should be dropped */ -static inline int -packet_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb) -{ - if (brvcc->filter.netmask == 0) - return 0; /* no filter in place */ - if (type == htons(ETH_P_IP) && - (((struct iphdr *)(skb->data))->daddr & brvcc->filter. - netmask) == brvcc->filter.prefix) - return 0; - if (type == htons(ETH_P_ARP)) - return 0; - /* - * TODO: we should probably filter ARPs too.. don't want to have - * them returning values that don't make sense, or is that ok? - */ - return 1; /* drop */ -} -#endif /* CONFIG_ATM_BR2684_IPFILTER */ - -static void br2684_close_vcc(struct br2684_vcc *brvcc) -{ - pr_debug("removing VCC %p from dev %p\n", brvcc, brvcc->device); - write_lock_irq(&devs_lock); - list_del(&brvcc->brvccs); - write_unlock_irq(&devs_lock); - brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */ - brvcc->atmvcc->release_cb = brvcc->old_release_cb; - brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */ - module_put(brvcc->old_owner); - kfree(brvcc); -} - -/* when AAL5 PDU comes in: */ -static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) -{ - struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); - struct net_device *net_dev = brvcc->device; - struct br2684_dev *brdev = BRPRIV(net_dev); - - pr_debug("\n"); - - if (unlikely(skb == NULL)) { - /* skb==NULL means VCC is being destroyed */ - br2684_close_vcc(brvcc); - if (list_empty(&brdev->brvccs)) { - write_lock_irq(&devs_lock); - list_del(&brdev->br2684_devs); - write_unlock_irq(&devs_lock); - unregister_netdev(net_dev); - free_netdev(net_dev); - } - return; - } - - skb_debug(skb); - atm_return(atmvcc, skb->truesize); - pr_debug("skb from brdev %p\n", brdev); - if (brvcc->encaps == e_llc) { - - if (skb->len > 7 && skb->data[7] == 0x01) - __skb_trim(skb, skb->len - 4); - - /* accept packets that have "ipv[46]" in the snap header */ - if ((skb->len >= (sizeof(llc_oui_ipv4))) && - (memcmp(skb->data, llc_oui_ipv4, - sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { - if (memcmp(skb->data + 6, ethertype_ipv6, - sizeof(ethertype_ipv6)) == 0) - skb->protocol = htons(ETH_P_IPV6); - else if (memcmp(skb->data + 6, ethertype_ipv4, - sizeof(ethertype_ipv4)) == 0) - skb->protocol = htons(ETH_P_IP); - else - goto error; - skb_pull(skb, sizeof(llc_oui_ipv4)); - skb_reset_network_header(skb); - skb->pkt_type = PACKET_HOST; - /* - * Let us waste some time for checking the encapsulation. - * Note, that only 7 char is checked so frames with a valid FCS - * are also accepted (but FCS is not checked of course). - */ - } else if ((skb->len >= sizeof(llc_oui_pid_pad)) && - (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) { - skb_pull(skb, sizeof(llc_oui_pid_pad)); - skb->protocol = eth_type_trans(skb, net_dev); - } else - goto error; - - } else { /* e_vc */ - if (brdev->payload == p_routed) { - struct iphdr *iph; - - skb_reset_network_header(skb); - iph = ip_hdr(skb); - if (iph->version == 4) - skb->protocol = htons(ETH_P_IP); - else if (iph->version == 6) - skb->protocol = htons(ETH_P_IPV6); - else - goto error; - skb->pkt_type = PACKET_HOST; - } else { /* p_bridged */ - /* first 2 chars should be 0 */ - if (memcmp(skb->data, pad, BR2684_PAD_LEN) != 0) - goto error; - skb_pull(skb, BR2684_PAD_LEN); - skb->protocol = eth_type_trans(skb, net_dev); - } - } - -#ifdef CONFIG_ATM_BR2684_IPFILTER - if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) - goto dropped; -#endif /* CONFIG_ATM_BR2684_IPFILTER */ - skb->dev = net_dev; - ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ - pr_debug("received packet's protocol: %x\n", ntohs(skb->protocol)); - skb_debug(skb); - /* sigh, interface is down? */ - if (unlikely(!(net_dev->flags & IFF_UP))) - goto dropped; - net_dev->stats.rx_packets++; - net_dev->stats.rx_bytes += skb->len; - memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); - netif_rx(skb); - return; - -dropped: - net_dev->stats.rx_dropped++; - goto free_skb; -error: - net_dev->stats.rx_errors++; -free_skb: - dev_kfree_skb(skb); -} - -/* - * Assign a vcc to a dev - * Note: we do not have explicit unassign, but look at _push() - */ -static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) -{ - struct br2684_vcc *brvcc; - struct br2684_dev *brdev; - struct net_device *net_dev; - struct atm_backend_br2684 be; - int err; - - if (copy_from_user(&be, arg, sizeof be)) - return -EFAULT; - brvcc = kzalloc_obj(struct br2684_vcc); - if (!brvcc) - return -ENOMEM; - /* - * Allow two packets in the ATM queue. One actually being sent, and one - * for the ATM 'TX done' handler to send. It shouldn't take long to get - * the next one from the netdev queue, when we need it. More than that - * would be bufferbloat. - */ - atomic_set(&brvcc->qspace, 2); - write_lock_irq(&devs_lock); - net_dev = br2684_find_dev(&be.ifspec); - if (net_dev == NULL) { - pr_err("tried to attach to non-existent device\n"); - err = -ENXIO; - goto error; - } - brdev = BRPRIV(net_dev); - if (atmvcc->push == NULL) { - err = -EBADFD; - goto error; - } - if (!list_empty(&brdev->brvccs)) { - /* Only 1 VCC/dev right now */ - err = -EEXIST; - goto error; - } - if (be.fcs_in != BR2684_FCSIN_NO || - be.fcs_out != BR2684_FCSOUT_NO || - be.fcs_auto || be.has_vpiid || be.send_padding || - (be.encaps != BR2684_ENCAPS_VC && - be.encaps != BR2684_ENCAPS_LLC) || - be.min_size != 0) { - err = -EINVAL; - goto error; - } - pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc); - if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { - unsigned char *esi = atmvcc->dev->esi; - const u8 one = 1; - - if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) - dev_addr_set(net_dev, esi); - else - dev_addr_mod(net_dev, 2, &one, 1); - } - list_add(&brvcc->brvccs, &brdev->brvccs); - write_unlock_irq(&devs_lock); - brvcc->device = net_dev; - brvcc->atmvcc = atmvcc; - atmvcc->user_back = brvcc; - brvcc->encaps = (enum br2684_encaps)be.encaps; - brvcc->old_push = atmvcc->push; - brvcc->old_pop = atmvcc->pop; - brvcc->old_release_cb = atmvcc->release_cb; - brvcc->old_owner = atmvcc->owner; - barrier(); - atmvcc->push = br2684_push; - atmvcc->pop = br2684_pop; - atmvcc->release_cb = br2684_release_cb; - atmvcc->owner = THIS_MODULE; - - /* initialize netdev carrier state */ - if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) - netif_carrier_off(net_dev); - else - netif_carrier_on(net_dev); - - __module_get(THIS_MODULE); - - /* re-process everything received between connection setup and - backend setup */ - vcc_process_recv_queue(atmvcc); - return 0; - -error: - write_unlock_irq(&devs_lock); - kfree(brvcc); - return err; -} - -static const struct net_device_ops br2684_netdev_ops = { - .ndo_start_xmit = br2684_start_xmit, - .ndo_set_mac_address = br2684_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops br2684_netdev_ops_routed = { - .ndo_start_xmit = br2684_start_xmit, - .ndo_set_mac_address = br2684_mac_addr, -}; - -static void br2684_setup(struct net_device *netdev) -{ - struct br2684_dev *brdev = BRPRIV(netdev); - - ether_setup(netdev); - netdev->hard_header_len += sizeof(llc_oui_pid_pad); /* worst case */ - brdev->net_dev = netdev; - - netdev->netdev_ops = &br2684_netdev_ops; - - INIT_LIST_HEAD(&brdev->brvccs); -} - -static void br2684_setup_routed(struct net_device *netdev) -{ - struct br2684_dev *brdev = BRPRIV(netdev); - - brdev->net_dev = netdev; - netdev->hard_header_len = sizeof(llc_oui_ipv4); /* worst case */ - netdev->netdev_ops = &br2684_netdev_ops_routed; - netdev->addr_len = 0; - netdev->mtu = ETH_DATA_LEN; - netdev->min_mtu = 0; - netdev->max_mtu = ETH_MAX_MTU; - netdev->type = ARPHRD_PPP; - netdev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - netdev->tx_queue_len = 100; - INIT_LIST_HEAD(&brdev->brvccs); -} - -static int br2684_create(void __user *arg) -{ - int err; - struct net_device *netdev; - struct br2684_dev *brdev; - struct atm_newif_br2684 ni; - enum br2684_payload payload; - - pr_debug("\n"); - - if (copy_from_user(&ni, arg, sizeof ni)) - return -EFAULT; - - if (ni.media & BR2684_FLAG_ROUTED) - payload = p_routed; - else - payload = p_bridged; - ni.media &= 0xffff; /* strip flags */ - - if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) - return -EINVAL; - - netdev = alloc_netdev(sizeof(struct br2684_dev), - ni.ifname[0] ? ni.ifname : "nas%d", - NET_NAME_UNKNOWN, - (payload == p_routed) ? br2684_setup_routed : br2684_setup); - if (!netdev) - return -ENOMEM; - - brdev = BRPRIV(netdev); - - pr_debug("registered netdev %s\n", netdev->name); - /* open, stop, do_ioctl ? */ - err = register_netdev(netdev); - if (err < 0) { - pr_err("register_netdev failed\n"); - free_netdev(netdev); - return err; - } - - write_lock_irq(&devs_lock); - - brdev->payload = payload; - - if (list_empty(&br2684_devs)) { - /* 1st br2684 device */ - brdev->number = 1; - } else - brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; - - list_add_tail(&brdev->br2684_devs, &br2684_devs); - write_unlock_irq(&devs_lock); - return 0; -} - -/* - * This handles ioctls actually performed on our vcc - we must return - * -ENOIOCTLCMD for any unrecognized ioctl - */ -static int br2684_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) -{ - struct atm_vcc *atmvcc = ATM_SD(sock); - void __user *argp = (void __user *)arg; - atm_backend_t b; - - int err; - switch (cmd) { - case ATM_SETBACKEND: - case ATM_NEWBACKENDIF: - err = get_user(b, (atm_backend_t __user *) argp); - if (err) - return -EFAULT; - if (b != ATM_BACKEND_BR2684) - return -ENOIOCTLCMD; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (cmd == ATM_SETBACKEND) { - if (sock->state != SS_CONNECTED) - return -EINVAL; - return br2684_regvcc(atmvcc, argp); - } else { - return br2684_create(argp); - } -#ifdef CONFIG_ATM_BR2684_IPFILTER - case BR2684_SETFILT: - if (atmvcc->push != br2684_push) - return -ENOIOCTLCMD; - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - err = br2684_setfilt(atmvcc, argp); - - return err; -#endif /* CONFIG_ATM_BR2684_IPFILTER */ - } - return -ENOIOCTLCMD; -} - -static struct atm_ioctl br2684_ioctl_ops = { - .owner = THIS_MODULE, - .ioctl = br2684_ioctl, -}; - -#ifdef CONFIG_PROC_FS -static void *br2684_seq_start(struct seq_file *seq, loff_t * pos) - __acquires(devs_lock) -{ - read_lock(&devs_lock); - return seq_list_start(&br2684_devs, *pos); -} - -static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t * pos) -{ - return seq_list_next(v, &br2684_devs, pos); -} - -static void br2684_seq_stop(struct seq_file *seq, void *v) - __releases(devs_lock) -{ - read_unlock(&devs_lock); -} - -static int br2684_seq_show(struct seq_file *seq, void *v) -{ - const struct br2684_dev *brdev = list_entry(v, struct br2684_dev, - br2684_devs); - const struct net_device *net_dev = brdev->net_dev; - const struct br2684_vcc *brvcc; - - seq_printf(seq, "dev %.16s: num=%d, mac=%pM (%s)\n", - net_dev->name, - brdev->number, - net_dev->dev_addr, - brdev->mac_was_set ? "set" : "auto"); - - list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { - seq_printf(seq, " vcc %d.%d.%d: encaps=%s payload=%s" - ", failed copies %u/%u" - "\n", brvcc->atmvcc->dev->number, - brvcc->atmvcc->vpi, brvcc->atmvcc->vci, - (brvcc->encaps == e_llc) ? "LLC" : "VC", - (brdev->payload == p_bridged) ? "bridged" : "routed", - brvcc->copies_failed, brvcc->copies_needed); -#ifdef CONFIG_ATM_BR2684_IPFILTER - if (brvcc->filter.netmask != 0) - seq_printf(seq, " filter=%pI4/%pI4\n", - &brvcc->filter.prefix, - &brvcc->filter.netmask); -#endif /* CONFIG_ATM_BR2684_IPFILTER */ - } - return 0; -} - -static const struct seq_operations br2684_seq_ops = { - .start = br2684_seq_start, - .next = br2684_seq_next, - .stop = br2684_seq_stop, - .show = br2684_seq_show, -}; - -extern struct proc_dir_entry *atm_proc_root; /* from proc.c */ -#endif /* CONFIG_PROC_FS */ - -static int __init br2684_init(void) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *p; - p = proc_create_seq("br2684", 0, atm_proc_root, &br2684_seq_ops); - if (p == NULL) - return -ENOMEM; -#endif - register_atm_ioctl(&br2684_ioctl_ops); - register_atmdevice_notifier(&atm_dev_notifier); - return 0; -} - -static void __exit br2684_exit(void) -{ - struct net_device *net_dev; - struct br2684_dev *brdev; - struct br2684_vcc *brvcc; - deregister_atm_ioctl(&br2684_ioctl_ops); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("br2684", atm_proc_root); -#endif - - - unregister_atmdevice_notifier(&atm_dev_notifier); - - while (!list_empty(&br2684_devs)) { - net_dev = list_entry_brdev(br2684_devs.next); - brdev = BRPRIV(net_dev); - while (!list_empty(&brdev->brvccs)) { - brvcc = list_entry_brvcc(brdev->brvccs.next); - br2684_close_vcc(brvcc); - } - - list_del(&brdev->br2684_devs); - unregister_netdev(net_dev); - free_netdev(net_dev); - } -} - -module_init(br2684_init); -module_exit(br2684_exit); - -MODULE_AUTHOR("Marcell GAL"); -MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5"); -MODULE_LICENSE("GPL"); diff --git a/net/atm/clip.c b/net/atm/clip.c deleted file mode 100644 index 516b2214680b..000000000000 --- a/net/atm/clip.c +++ /dev/null @@ -1,960 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* net/atm/clip.c - RFC1577 Classical IP over ATM */ - -/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include /* for UINT_MAX */ -#include -#include -#include -#include -#include -#include -#include /* for some manifest constants */ -#include -#include -#include -#include -#include -#include -#include /* for net/route.h */ -#include /* for struct sockaddr_in */ -#include /* for IFF_UP */ -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for struct rtable and routing */ -#include /* icmp_send */ -#include -#include /* for HZ */ -#include -#include /* for htons etc. */ -#include - -#include "common.h" -#include "resources.h" -#include - -static struct net_device *clip_devs; -static struct atm_vcc __rcu *atmarpd; -static DEFINE_MUTEX(atmarpd_lock); -static struct timer_list idle_timer; -static const struct neigh_ops clip_neigh_ops; - -static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip) -{ - struct sock *sk; - struct atmarp_ctrl *ctrl; - struct atm_vcc *vcc; - struct sk_buff *skb; - int err = 0; - - pr_debug("(%d)\n", type); - - rcu_read_lock(); - vcc = rcu_dereference(atmarpd); - if (!vcc) { - err = -EUNATCH; - goto unlock; - } - skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC); - if (!skb) { - err = -ENOMEM; - goto unlock; - } - ctrl = skb_put(skb, sizeof(struct atmarp_ctrl)); - ctrl->type = type; - ctrl->itf_num = itf; - ctrl->ip = ip; - atm_force_charge(vcc, skb->truesize); - - sk = sk_atm(vcc); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); -unlock: - rcu_read_unlock(); - return err; -} - -static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry) -{ - pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh); - clip_vcc->entry = entry; - clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */ - clip_vcc->next = entry->vccs; - entry->vccs = clip_vcc; - entry->neigh->used = jiffies; -} - -static void unlink_clip_vcc(struct clip_vcc *clip_vcc) -{ - struct atmarp_entry *entry = clip_vcc->entry; - struct clip_vcc **walk; - - if (!entry) { - pr_err("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc); - return; - } - netif_tx_lock_bh(entry->neigh->dev); /* block clip_start_xmit() */ - entry->neigh->used = jiffies; - for (walk = &entry->vccs; *walk; walk = &(*walk)->next) - if (*walk == clip_vcc) { - int error; - - *walk = clip_vcc->next; /* atomic */ - clip_vcc->entry = NULL; - if (clip_vcc->xoff) - netif_wake_queue(entry->neigh->dev); - if (entry->vccs) - goto out; - entry->expires = jiffies - 1; - /* force resolution or expiration */ - error = neigh_update(entry->neigh, NULL, NUD_NONE, - NEIGH_UPDATE_F_ADMIN, 0); - if (error) - pr_err("neigh_update failed with %d\n", error); - goto out; - } - pr_err("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc); -out: - netif_tx_unlock_bh(entry->neigh->dev); -} - -/* The neighbour entry n->lock is held. */ -static int neigh_check_cb(struct neighbour *n) -{ - struct atmarp_entry *entry = neighbour_priv(n); - struct clip_vcc *cv; - - if (n->ops != &clip_neigh_ops) - return 0; - for (cv = entry->vccs; cv; cv = cv->next) { - unsigned long exp = cv->last_use + cv->idle_timeout; - - if (cv->idle_timeout && time_after(jiffies, exp)) { - pr_debug("releasing vcc %p->%p of entry %p\n", - cv, cv->vcc, entry); - vcc_release_async(cv->vcc, -ETIMEDOUT); - } - } - - if (entry->vccs || time_before(jiffies, entry->expires)) - return 0; - - if (refcount_read(&n->refcnt) > 1) { - struct sk_buff *skb; - - pr_debug("destruction postponed with ref %d\n", - refcount_read(&n->refcnt)); - - while ((skb = skb_dequeue(&n->arp_queue)) != NULL) - dev_kfree_skb(skb); - - return 0; - } - - pr_debug("expired neigh %p\n", n); - return 1; -} - -static void idle_timer_check(struct timer_list *unused) -{ - spin_lock(&arp_tbl.lock); - __neigh_for_each_release(&arp_tbl, neigh_check_cb); - mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ); - spin_unlock(&arp_tbl.lock); -} - -static int clip_arp_rcv(struct sk_buff *skb) -{ - struct atm_vcc *vcc; - - pr_debug("\n"); - vcc = ATM_SKB(skb)->vcc; - if (!vcc || !atm_charge(vcc, skb->truesize)) { - dev_kfree_skb_any(skb); - return 0; - } - pr_debug("pushing to %p\n", vcc); - pr_debug("using %p\n", CLIP_VCC(vcc)->old_push); - CLIP_VCC(vcc)->old_push(vcc, skb); - return 0; -} - -static const unsigned char llc_oui[] = { - 0xaa, /* DSAP: non-ISO */ - 0xaa, /* SSAP: non-ISO */ - 0x03, /* Ctrl: Unnumbered Information Command PDU */ - 0x00, /* OUI: EtherType */ - 0x00, - 0x00 -}; - -static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct clip_vcc *clip_vcc = CLIP_VCC(vcc); - - pr_debug("\n"); - - if (!skb) { - pr_debug("removing VCC %p\n", clip_vcc); - if (clip_vcc->entry) - unlink_clip_vcc(clip_vcc); - clip_vcc->old_push(vcc, NULL); /* pass on the bad news */ - kfree(clip_vcc); - return; - } - atm_return(vcc, skb->truesize); - if (!clip_devs) { - kfree_skb(skb); - return; - } - - skb->dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : clip_devs; - /* clip_vcc->entry == NULL if we don't have an IP address yet */ - if (!skb->dev) { - dev_kfree_skb_any(skb); - return; - } - ATM_SKB(skb)->vcc = vcc; - skb_reset_mac_header(skb); - if (!clip_vcc->encap || - skb->len < RFC1483LLC_LEN || - memcmp(skb->data, llc_oui, sizeof(llc_oui))) - skb->protocol = htons(ETH_P_IP); - else { - skb->protocol = ((__be16 *)skb->data)[3]; - skb_pull(skb, RFC1483LLC_LEN); - if (skb->protocol == htons(ETH_P_ARP)) { - skb->dev->stats.rx_packets++; - skb->dev->stats.rx_bytes += skb->len; - clip_arp_rcv(skb); - return; - } - } - clip_vcc->last_use = jiffies; - skb->dev->stats.rx_packets++; - skb->dev->stats.rx_bytes += skb->len; - memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); - netif_rx(skb); -} - -/* - * Note: these spinlocks _must_not_ block on non-SMP. The only goal is that - * clip_pop is atomic with respect to the critical section in clip_start_xmit. - */ - -static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct clip_vcc *clip_vcc = CLIP_VCC(vcc); - struct net_device *dev = skb->dev; - int old; - unsigned long flags; - - pr_debug("(vcc %p)\n", vcc); - clip_vcc->old_pop(vcc, skb); - /* skb->dev == NULL in outbound ARP packets */ - if (!dev) - return; - spin_lock_irqsave(&PRIV(dev)->xoff_lock, flags); - if (atm_may_send(vcc, 0)) { - old = xchg(&clip_vcc->xoff, 0); - if (old) - netif_wake_queue(dev); - } - spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags); -} - -static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) -{ - __be32 *ip = (__be32 *) neigh->primary_key; - - pr_debug("(neigh %p, skb %p)\n", neigh, skb); - to_atmarpd(act_need, PRIV(neigh->dev)->number, *ip); -} - -static void clip_neigh_error(struct neighbour *neigh, struct sk_buff *skb) -{ -#ifndef CONFIG_ATM_CLIP_NO_ICMP - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); -#endif - kfree_skb(skb); -} - -static const struct neigh_ops clip_neigh_ops = { - .family = AF_INET, - .solicit = clip_neigh_solicit, - .error_report = clip_neigh_error, - .output = neigh_direct_output, - .connected_output = neigh_direct_output, -}; - -static int clip_constructor(struct net_device *dev, struct neighbour *neigh) -{ - struct atmarp_entry *entry = neighbour_priv(neigh); - - if (neigh->tbl->family != AF_INET) - return -EINVAL; - - if (neigh->type != RTN_UNICAST) - return -EINVAL; - - neigh->nud_state = NUD_NONE; - neigh->ops = &clip_neigh_ops; - neigh->output = neigh->ops->output; - entry->neigh = neigh; - entry->vccs = NULL; - entry->expires = jiffies - 1; - - return 0; -} - -/* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */ - -/* - * We play with the resolve flag: 0 and 1 have the usual meaning, but -1 means - * to allocate the neighbour entry but not to ask atmarpd for resolution. Also, - * don't increment the usage count. This is used to create entries in - * clip_setentry. - */ - -static int clip_encap(struct atm_vcc *vcc, int mode) -{ - if (!CLIP_VCC(vcc)) - return -EBADFD; - - CLIP_VCC(vcc)->encap = mode; - return 0; -} - -static netdev_tx_t clip_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct clip_priv *clip_priv = PRIV(dev); - struct dst_entry *dst = skb_dst(skb); - struct atmarp_entry *entry; - struct neighbour *n; - struct atm_vcc *vcc; - struct rtable *rt; - __be32 *daddr; - int old; - unsigned long flags; - - pr_debug("(skb %p)\n", skb); - if (!dst) { - pr_err("skb_dst(skb) == NULL\n"); - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - rt = dst_rtable(dst); - if (rt->rt_gw_family == AF_INET) - daddr = &rt->rt_gw4; - else - daddr = &ip_hdr(skb)->daddr; - n = dst_neigh_lookup(dst, daddr); - if (!n) { - pr_err("NO NEIGHBOUR !\n"); - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - entry = neighbour_priv(n); - if (!entry->vccs) { - if (time_after(jiffies, entry->expires)) { - /* should be resolved */ - entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ; - to_atmarpd(act_need, PRIV(dev)->number, *((__be32 *)n->primary_key)); - } - if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS) - skb_queue_tail(&entry->neigh->arp_queue, skb); - else { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - } - goto out_release_neigh; - } - pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); - ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; - pr_debug("using neighbour %p, vcc %p\n", n, vcc); - if (entry->vccs->encap) { - void *here; - - here = skb_push(skb, RFC1483LLC_LEN); - memcpy(here, llc_oui, sizeof(llc_oui)); - ((__be16 *) here)[3] = skb->protocol; - } - atm_account_tx(vcc, skb); - entry->vccs->last_use = jiffies; - pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev); - old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */ - if (old) { - pr_warn("XOFF->XOFF transition\n"); - goto out_release_neigh; - } - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - vcc->send(vcc, skb); - if (atm_may_send(vcc, 0)) { - entry->vccs->xoff = 0; - goto out_release_neigh; - } - spin_lock_irqsave(&clip_priv->xoff_lock, flags); - netif_stop_queue(dev); /* XOFF -> throttle immediately */ - barrier(); - if (!entry->vccs->xoff) - netif_start_queue(dev); - /* Oh, we just raced with clip_pop. netif_start_queue should be - good enough, because nothing should really be asleep because - of the brief netif_stop_queue. If this isn't true or if it - changes, use netif_wake_queue instead. */ - spin_unlock_irqrestore(&clip_priv->xoff_lock, flags); -out_release_neigh: - neigh_release(n); - return NETDEV_TX_OK; -} - -static int clip_mkip(struct atm_vcc *vcc, int timeout) -{ - struct clip_vcc *clip_vcc; - - if (!vcc->push) - return -EBADFD; - if (vcc->user_back) - return -EINVAL; - clip_vcc = kmalloc_obj(struct clip_vcc); - if (!clip_vcc) - return -ENOMEM; - pr_debug("%p vcc %p\n", clip_vcc, vcc); - clip_vcc->vcc = vcc; - vcc->user_back = clip_vcc; - set_bit(ATM_VF_IS_CLIP, &vcc->flags); - clip_vcc->entry = NULL; - clip_vcc->xoff = 0; - clip_vcc->encap = 1; - clip_vcc->last_use = jiffies; - clip_vcc->idle_timeout = timeout * HZ; - clip_vcc->old_push = vcc->push; - clip_vcc->old_pop = vcc->pop; - vcc->push = clip_push; - vcc->pop = clip_pop; - - /* re-process everything received between connection setup and MKIP */ - vcc_process_recv_queue(vcc); - - return 0; -} - -static int clip_setentry(struct atm_vcc *vcc, __be32 ip) -{ - struct neighbour *neigh; - struct atmarp_entry *entry; - int error; - struct clip_vcc *clip_vcc; - struct rtable *rt; - - if (vcc->push != clip_push) { - pr_warn("non-CLIP VCC\n"); - return -EBADF; - } - clip_vcc = CLIP_VCC(vcc); - if (!ip) { - if (!clip_vcc->entry) { - pr_err("hiding hidden ATMARP entry\n"); - return 0; - } - pr_debug("remove\n"); - unlink_clip_vcc(clip_vcc); - return 0; - } - rt = ip_route_output(&init_net, ip, 0, 0, 0, RT_SCOPE_LINK); - if (IS_ERR(rt)) - return PTR_ERR(rt); - neigh = __neigh_lookup(&arp_tbl, &ip, rt->dst.dev, 1); - ip_rt_put(rt); - if (!neigh) - return -ENOMEM; - entry = neighbour_priv(neigh); - if (entry != clip_vcc->entry) { - if (!clip_vcc->entry) - pr_debug("add\n"); - else { - pr_debug("update\n"); - unlink_clip_vcc(clip_vcc); - } - link_vcc(clip_vcc, entry); - } - error = neigh_update(neigh, llc_oui, NUD_PERMANENT, - NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN, 0); - neigh_release(neigh); - return error; -} - -static const struct net_device_ops clip_netdev_ops = { - .ndo_start_xmit = clip_start_xmit, - .ndo_neigh_construct = clip_constructor, -}; - -static void clip_setup(struct net_device *dev) -{ - dev->netdev_ops = &clip_netdev_ops; - dev->type = ARPHRD_ATM; - dev->neigh_priv_len = sizeof(struct atmarp_entry); - dev->hard_header_len = RFC1483LLC_LEN; - dev->mtu = RFC1626_MTU; - dev->tx_queue_len = 100; /* "normal" queue (packets) */ - /* When using a "real" qdisc, the qdisc determines the queue */ - /* length. tx_queue_len is only used for the default case, */ - /* without any more elaborate queuing. 100 is a reasonable */ - /* compromise between decent burst-tolerance and protection */ - /* against memory hogs. */ - netif_keep_dst(dev); -} - -static int clip_create(int number) -{ - struct net_device *dev; - struct clip_priv *clip_priv; - int error; - - if (number != -1) { - for (dev = clip_devs; dev; dev = PRIV(dev)->next) - if (PRIV(dev)->number == number) - return -EEXIST; - } else { - number = 0; - for (dev = clip_devs; dev; dev = PRIV(dev)->next) - if (PRIV(dev)->number >= number) - number = PRIV(dev)->number + 1; - } - dev = alloc_netdev(sizeof(struct clip_priv), "", NET_NAME_UNKNOWN, - clip_setup); - if (!dev) - return -ENOMEM; - clip_priv = PRIV(dev); - sprintf(dev->name, "atm%d", number); - spin_lock_init(&clip_priv->xoff_lock); - clip_priv->number = number; - error = register_netdev(dev); - if (error) { - free_netdev(dev); - return error; - } - clip_priv->next = clip_devs; - clip_devs = dev; - pr_debug("registered (net:%s)\n", dev->name); - return number; -} - -static int clip_device_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - - if (event == NETDEV_UNREGISTER) - return NOTIFY_DONE; - - /* ignore non-CLIP devices */ - if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops) - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - pr_debug("NETDEV_UP\n"); - to_atmarpd(act_up, PRIV(dev)->number, 0); - break; - case NETDEV_GOING_DOWN: - pr_debug("NETDEV_DOWN\n"); - to_atmarpd(act_down, PRIV(dev)->number, 0); - break; - case NETDEV_CHANGE: - case NETDEV_CHANGEMTU: - pr_debug("NETDEV_CHANGE*\n"); - to_atmarpd(act_change, PRIV(dev)->number, 0); - break; - } - return NOTIFY_DONE; -} - -static int clip_inet_event(struct notifier_block *this, unsigned long event, - void *ifa) -{ - struct in_device *in_dev; - struct netdev_notifier_info info; - - in_dev = ((struct in_ifaddr *)ifa)->ifa_dev; - /* - * Transitions are of the down-change-up type, so it's sufficient to - * handle the change on up. - */ - if (event != NETDEV_UP) - return NOTIFY_DONE; - netdev_notifier_info_init(&info, in_dev->dev); - return clip_device_event(this, NETDEV_CHANGE, &info); -} - -static struct notifier_block clip_dev_notifier = { - .notifier_call = clip_device_event, -}; - - - -static struct notifier_block clip_inet_notifier = { - .notifier_call = clip_inet_event, -}; - - - -static void atmarpd_close(struct atm_vcc *vcc) -{ - pr_debug("\n"); - - mutex_lock(&atmarpd_lock); - RCU_INIT_POINTER(atmarpd, NULL); - mutex_unlock(&atmarpd_lock); - - synchronize_rcu(); - skb_queue_purge(&sk_atm(vcc)->sk_receive_queue); - - pr_debug("(done)\n"); - module_put(THIS_MODULE); -} - -static int atmarpd_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - atm_return_tx(vcc, skb); - dev_kfree_skb_any(skb); - return 0; -} - -static const struct atmdev_ops atmarpd_dev_ops = { - .close = atmarpd_close, - .send = atmarpd_send -}; - - -static struct atm_dev atmarpd_dev = { - .ops = &atmarpd_dev_ops, - .type = "arpd", - .number = 999, - .lock = __SPIN_LOCK_UNLOCKED(atmarpd_dev.lock) -}; - - -static int atm_init_atmarp(struct atm_vcc *vcc) -{ - if (vcc->push == clip_push) - return -EINVAL; - - mutex_lock(&atmarpd_lock); - if (atmarpd) { - mutex_unlock(&atmarpd_lock); - return -EADDRINUSE; - } - - mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ); - - rcu_assign_pointer(atmarpd, vcc); - set_bit(ATM_VF_META, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - /* allow replies and avoid getting closed if signaling dies */ - vcc->dev = &atmarpd_dev; - vcc_insert_socket(sk_atm(vcc)); - vcc->push = NULL; - vcc->pop = NULL; /* crash */ - vcc->push_oam = NULL; /* crash */ - mutex_unlock(&atmarpd_lock); - return 0; -} - -static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct atm_vcc *vcc = ATM_SD(sock); - struct sock *sk = sock->sk; - int err = 0; - - switch (cmd) { - case SIOCMKCLIP: - case ATMARPD_CTRL: - case ATMARP_MKIP: - case ATMARP_SETENTRY: - case ATMARP_ENCAP: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; - default: - return -ENOIOCTLCMD; - } - - switch (cmd) { - case SIOCMKCLIP: - err = clip_create(arg); - break; - case ATMARPD_CTRL: - lock_sock(sk); - err = atm_init_atmarp(vcc); - if (!err) { - sock->state = SS_CONNECTED; - __module_get(THIS_MODULE); - } - release_sock(sk); - break; - case ATMARP_MKIP: - lock_sock(sk); - err = clip_mkip(vcc, arg); - release_sock(sk); - break; - case ATMARP_SETENTRY: - err = clip_setentry(vcc, (__force __be32)arg); - break; - case ATMARP_ENCAP: - err = clip_encap(vcc, arg); - break; - } - return err; -} - -static struct atm_ioctl clip_ioctl_ops = { - .owner = THIS_MODULE, - .ioctl = clip_ioctl, -}; - -#ifdef CONFIG_PROC_FS - -static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr) -{ - static int code[] = { 1, 2, 10, 6, 1, 0 }; - static int e164[] = { 1, 8, 4, 6, 1, 0 }; - - if (*addr->sas_addr.pub) { - seq_printf(seq, "%s", addr->sas_addr.pub); - if (*addr->sas_addr.prv) - seq_putc(seq, '+'); - } else if (!*addr->sas_addr.prv) { - seq_printf(seq, "%s", "(none)"); - return; - } - if (*addr->sas_addr.prv) { - unsigned char *prv = addr->sas_addr.prv; - int *fields; - int i, j; - - fields = *prv == ATM_AFI_E164 ? e164 : code; - for (i = 0; fields[i]; i++) { - for (j = fields[i]; j; j--) - seq_printf(seq, "%02X", *prv++); - if (fields[i + 1]) - seq_putc(seq, '.'); - } - } -} - -/* This means the neighbour entry has no attached VCC objects. */ -#define SEQ_NO_VCC_TOKEN ((void *) 2) - -static void atmarp_info(struct seq_file *seq, struct neighbour *n, - struct atmarp_entry *entry, struct clip_vcc *clip_vcc) -{ - struct net_device *dev = n->dev; - unsigned long exp; - char buf[17]; - int svc, llc, off; - - svc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || - (sk_atm(clip_vcc->vcc)->sk_family == AF_ATMSVC)); - - llc = ((clip_vcc == SEQ_NO_VCC_TOKEN) || clip_vcc->encap); - - if (clip_vcc == SEQ_NO_VCC_TOKEN) - exp = entry->neigh->used; - else - exp = clip_vcc->last_use; - - exp = (jiffies - exp) / HZ; - - seq_printf(seq, "%-6s%-4s%-4s%5ld ", - dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp); - - off = scnprintf(buf, sizeof(buf) - 1, "%pI4", n->primary_key); - while (off < 16) - buf[off++] = ' '; - buf[off] = '\0'; - seq_printf(seq, "%s", buf); - - if (clip_vcc == SEQ_NO_VCC_TOKEN) { - if (time_before(jiffies, entry->expires)) - seq_printf(seq, "(resolving)\n"); - else - seq_printf(seq, "(expired, ref %d)\n", - refcount_read(&entry->neigh->refcnt)); - } else if (!svc) { - seq_printf(seq, "%d.%d.%d\n", - clip_vcc->vcc->dev->number, - clip_vcc->vcc->vpi, clip_vcc->vcc->vci); - } else { - svc_addr(seq, &clip_vcc->vcc->remote); - seq_putc(seq, '\n'); - } -} - -struct clip_seq_state { - /* This member must be first. */ - struct neigh_seq_state ns; - - /* Local to clip specific iteration. */ - struct clip_vcc *vcc; -}; - -static struct clip_vcc *clip_seq_next_vcc(struct atmarp_entry *e, - struct clip_vcc *curr) -{ - if (!curr) { - curr = e->vccs; - if (!curr) - return SEQ_NO_VCC_TOKEN; - return curr; - } - if (curr == SEQ_NO_VCC_TOKEN) - return NULL; - - curr = curr->next; - - return curr; -} - -static void *clip_seq_vcc_walk(struct clip_seq_state *state, - struct atmarp_entry *e, loff_t * pos) -{ - struct clip_vcc *vcc = state->vcc; - - vcc = clip_seq_next_vcc(e, vcc); - if (vcc && pos != NULL) { - while (*pos) { - vcc = clip_seq_next_vcc(e, vcc); - if (!vcc) - break; - --(*pos); - } - } - state->vcc = vcc; - - return vcc; -} - -static void *clip_seq_sub_iter(struct neigh_seq_state *_state, - struct neighbour *n, loff_t * pos) -{ - struct clip_seq_state *state = (struct clip_seq_state *)_state; - - if (n->dev->type != ARPHRD_ATM) - return NULL; - - return clip_seq_vcc_walk(state, neighbour_priv(n), pos); -} - -static void *clip_seq_start(struct seq_file *seq, loff_t * pos) -{ - struct clip_seq_state *state = seq->private; - state->ns.neigh_sub_iter = clip_seq_sub_iter; - return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_NEIGH_ONLY); -} - -static int clip_seq_show(struct seq_file *seq, void *v) -{ - static char atm_arp_banner[] = - "IPitf TypeEncp Idle IP address ATM address\n"; - - if (v == SEQ_START_TOKEN) { - seq_puts(seq, atm_arp_banner); - } else { - struct clip_seq_state *state = seq->private; - struct clip_vcc *vcc = state->vcc; - struct neighbour *n = v; - - atmarp_info(seq, n, neighbour_priv(n), vcc); - } - return 0; -} - -static const struct seq_operations arp_seq_ops = { - .start = clip_seq_start, - .next = neigh_seq_next, - .stop = neigh_seq_stop, - .show = clip_seq_show, -}; -#endif - -static void atm_clip_exit_noproc(void); - -static int __init atm_clip_init(void) -{ - register_atm_ioctl(&clip_ioctl_ops); - register_netdevice_notifier(&clip_dev_notifier); - register_inetaddr_notifier(&clip_inet_notifier); - - timer_setup(&idle_timer, idle_timer_check, 0); - -#ifdef CONFIG_PROC_FS - { - struct proc_dir_entry *p; - - p = proc_create_net("arp", 0444, atm_proc_root, &arp_seq_ops, - sizeof(struct clip_seq_state)); - if (!p) { - pr_err("Unable to initialize /proc/net/atm/arp\n"); - atm_clip_exit_noproc(); - return -ENOMEM; - } - } -#endif - - return 0; -} - -static void atm_clip_exit_noproc(void) -{ - struct net_device *dev, *next; - - unregister_inetaddr_notifier(&clip_inet_notifier); - unregister_netdevice_notifier(&clip_dev_notifier); - - deregister_atm_ioctl(&clip_ioctl_ops); - - /* First, stop the idle timer, so it stops banging - * on the table. - */ - timer_delete_sync(&idle_timer); - - dev = clip_devs; - while (dev) { - next = PRIV(dev)->next; - unregister_netdev(dev); - free_netdev(dev); - dev = next; - } -} - -static void __exit atm_clip_exit(void) -{ - remove_proc_entry("arp", atm_proc_root); - - atm_clip_exit_noproc(); -} - -module_init(atm_clip_init); -module_exit(atm_clip_exit); -MODULE_AUTHOR("Werner Almesberger"); -MODULE_DESCRIPTION("Classical/IP over ATM interface"); -MODULE_LICENSE("GPL"); diff --git a/net/atm/lec.c b/net/atm/lec.c deleted file mode 100644 index 10e260acf602..000000000000 --- a/net/atm/lec.c +++ /dev/null @@ -1,2274 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * lec.c: Lan Emulation driver - * - * Marko Kiiskila - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include - -/* We are ethernet device */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* And atm device */ -#include -#include - -/* Proxy LEC knows about bridging */ -#if IS_ENABLED(CONFIG_BRIDGE) -#include "../bridge/br_private.h" - -static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; -#endif - -/* Modular too */ -#include -#include - -/* Hardening for Spectre-v1 */ -#include - -#include "lec.h" -#include "lec_arpc.h" -#include "resources.h" - -#define DUMP_PACKETS 0 /* - * 0 = None, - * 1 = 30 first bytes - * 2 = Whole packet - */ - -#define LEC_UNRES_QUE_LEN 8 /* - * number of tx packets to queue for a - * single destination while waiting for SVC - */ - -static int lec_open(struct net_device *dev); -static netdev_tx_t lec_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int lec_close(struct net_device *dev); -static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, - const unsigned char *mac_addr); -static int lec_arp_remove(struct lec_priv *priv, - struct lec_arp_table *to_remove); -/* LANE2 functions */ -static void lane2_associate_ind(struct net_device *dev, const u8 *mac_address, - const u8 *tlvs, u32 sizeoftlvs); -static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force, - u8 **tlvs, u32 *sizeoftlvs); -static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, - const u8 *tlvs, u32 sizeoftlvs); - -static int lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, - unsigned long permanent); -static void lec_arp_check_empties(struct lec_priv *priv, - struct atm_vcc *vcc, struct sk_buff *skb); -static void lec_arp_destroy(struct lec_priv *priv); -static void lec_arp_init(struct lec_priv *priv); -static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - const unsigned char *mac_to_find, - int is_rdesc, - struct lec_arp_table **ret_entry); -static void lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, - const unsigned char *atm_addr, - unsigned long remoteflag, - unsigned int targetless_le_arp); -static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id); -static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc); -static void lec_set_flush_tran_id(struct lec_priv *priv, - const unsigned char *atm_addr, - unsigned long tran_id); -static void lec_vcc_added(struct lec_priv *priv, - const struct atmlec_ioc *ioc_data, - struct atm_vcc *vcc, - void (*old_push)(struct atm_vcc *vcc, - struct sk_buff *skb)); -static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); - -/* must be done under lec_arp_lock */ -static inline void lec_arp_hold(struct lec_arp_table *entry) -{ - refcount_inc(&entry->usage); -} - -static inline void lec_arp_put(struct lec_arp_table *entry) -{ - if (refcount_dec_and_test(&entry->usage)) - kfree(entry); -} - -static struct lane2_ops lane2_ops = { - .resolve = lane2_resolve, /* spec 3.1.3 */ - .associate_req = lane2_associate_req, /* spec 3.1.4 */ - .associate_indicator = NULL /* spec 3.1.5 */ -}; - -static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -/* Device structures */ -static struct net_device *dev_lec[MAX_LEC_ITF]; -static DEFINE_MUTEX(lec_mutex); - -#if IS_ENABLED(CONFIG_BRIDGE) -static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) -{ - char *buff; - struct lec_priv *priv; - - /* - * Check if this is a BPDU. If so, ask zeppelin to send - * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit - * as the Config BPDU has - */ - buff = skb->data + skb->dev->hard_header_len; - if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) { - struct sock *sk; - struct sk_buff *skb2; - struct atmlec_msg *mesg; - - skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) - return; - skb2->len = sizeof(struct atmlec_msg); - mesg = (struct atmlec_msg *)skb2->data; - mesg->type = l_topology_change; - buff += 4; - mesg->content.normal.flag = *buff & 0x01; - /* 0x01 is topology change */ - - priv = netdev_priv(dev); - struct atm_vcc *vcc; - - rcu_read_lock(); - vcc = rcu_dereference(priv->lecd); - if (vcc) { - atm_force_charge(vcc, skb2->truesize); - sk = sk_atm(vcc); - skb_queue_tail(&sk->sk_receive_queue, skb2); - sk->sk_data_ready(sk); - } else { - dev_kfree_skb(skb2); - } - rcu_read_unlock(); - } -} -#endif /* IS_ENABLED(CONFIG_BRIDGE) */ - -/* - * Open/initialize the netdevice. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ - -static int lec_open(struct net_device *dev) -{ - netif_start_queue(dev); - - return 0; -} - -static void -lec_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned int len = skb->len; - - ATM_SKB(skb)->vcc = vcc; - atm_account_tx(vcc, skb); - - if (vcc->send(vcc, skb) < 0) { - dev->stats.tx_dropped++; - return; - } - - dev->stats.tx_packets++; - dev->stats.tx_bytes += len; -} - -static void lec_tx_timeout(struct net_device *dev, unsigned int txqueue) -{ - pr_info("%s\n", dev->name); - netif_trans_update(dev); - netif_wake_queue(dev); -} - -static netdev_tx_t lec_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct sk_buff *skb2; - struct lec_priv *priv = netdev_priv(dev); - struct lecdatahdr_8023 *lec_h; - struct atm_vcc *vcc; - struct lec_arp_table *entry; - unsigned char *dst; - int min_frame_size; - int is_rdesc; - - pr_debug("called\n"); - if (!rcu_access_pointer(priv->lecd)) { - pr_info("%s:No lecd attached\n", dev->name); - dev->stats.tx_errors++; - netif_stop_queue(dev); - kfree_skb(skb); - return NETDEV_TX_OK; - } - - pr_debug("skbuff head:%lx data:%lx tail:%lx end:%lx\n", - (long)skb->head, (long)skb->data, (long)skb_tail_pointer(skb), - (long)skb_end_pointer(skb)); -#if IS_ENABLED(CONFIG_BRIDGE) - if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0) - lec_handle_bridge(skb, dev); -#endif - - /* Make sure we have room for lec_id */ - if (skb_headroom(skb) < 2) { - pr_debug("reallocating skb\n"); - skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); - if (unlikely(!skb2)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } - consume_skb(skb); - skb = skb2; - } - skb_push(skb, 2); - - /* Put le header to place */ - lec_h = (struct lecdatahdr_8023 *)skb->data; - lec_h->le_header = htons(priv->lecid); - -#if DUMP_PACKETS >= 2 -#define MAX_DUMP_SKB 99 -#elif DUMP_PACKETS >= 1 -#define MAX_DUMP_SKB 30 -#endif -#if DUMP_PACKETS >= 1 - printk(KERN_DEBUG "%s: send datalen:%ld lecid:%4.4x\n", - dev->name, skb->len, priv->lecid); - print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1, - skb->data, min(skb->len, MAX_DUMP_SKB), true); -#endif /* DUMP_PACKETS >= 1 */ - - /* Minimum ethernet-frame size */ - min_frame_size = LEC_MINIMUM_8023_SIZE; - if (skb->len < min_frame_size) { - if ((skb->len + skb_tailroom(skb)) < min_frame_size) { - skb2 = skb_copy_expand(skb, 0, - min_frame_size - skb->truesize, - GFP_ATOMIC); - dev_kfree_skb(skb); - if (skb2 == NULL) { - dev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - skb = skb2; - } - skb_put(skb, min_frame_size - skb->len); - } - - /* Send to right vcc */ - is_rdesc = 0; - dst = lec_h->h_dest; - entry = NULL; - vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry); - pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", - dev->name, vcc, vcc ? vcc->flags : 0, entry); - if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) { - if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { - pr_debug("%s:queuing packet, MAC address %pM\n", - dev->name, lec_h->h_dest); - skb_queue_tail(&entry->tx_wait, skb); - } else { - pr_debug("%s:tx queue full or no arp entry, dropping, MAC address: %pM\n", - dev->name, lec_h->h_dest); - dev->stats.tx_dropped++; - dev_kfree_skb(skb); - } - goto out; - } -#if DUMP_PACKETS > 0 - printk(KERN_DEBUG "%s:sending to vpi:%d vci:%d\n", - dev->name, vcc->vpi, vcc->vci); -#endif /* DUMP_PACKETS > 0 */ - - while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { - pr_debug("emptying tx queue, MAC address %pM\n", lec_h->h_dest); - lec_send(vcc, skb2); - } - - lec_send(vcc, skb); - - if (!atm_may_send(vcc, 0)) { - struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc); - - vpriv->xoff = 1; - netif_stop_queue(dev); - - /* - * vcc->pop() might have occurred in between, making - * the vcc usuable again. Since xmit is serialized, - * this is the only situation we have to re-test. - */ - - if (atm_may_send(vcc, 0)) - netif_wake_queue(dev); - } - -out: - if (entry) - lec_arp_put(entry); - netif_trans_update(dev); - return NETDEV_TX_OK; -} - -/* The inverse routine to net_open(). */ -static int lec_close(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - static const u8 zero_addr[ETH_ALEN] = {}; - unsigned long flags; - struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = netdev_priv(dev); - struct atmlec_msg *mesg; - struct lec_arp_table *entry; - char *tmp; /* FIXME */ - - WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); - mesg = (struct atmlec_msg *)skb->data; - tmp = skb->data; - tmp += sizeof(struct atmlec_msg); - pr_debug("%s: msg from zeppelin:%d\n", dev->name, mesg->type); - switch (mesg->type) { - case l_set_mac_addr: - eth_hw_addr_set(dev, mesg->content.normal.mac_addr); - break; - case l_del_mac_addr: - eth_hw_addr_set(dev, zero_addr); - break; - case l_addr_delete: - lec_addr_delete(priv, mesg->content.normal.atm_addr, - mesg->content.normal.flag); - break; - case l_topology_change: - priv->topology_change = mesg->content.normal.flag; - break; - case l_flush_complete: - lec_flush_complete(priv, mesg->content.normal.flag); - break; - case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */ - spin_lock_irqsave(&priv->lec_arp_lock, flags); - entry = lec_arp_find(priv, mesg->content.normal.mac_addr); - lec_arp_remove(priv, entry); - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - - if (mesg->content.normal.no_source_le_narp) - break; - fallthrough; - case l_arp_update: - lec_arp_update(priv, mesg->content.normal.mac_addr, - mesg->content.normal.atm_addr, - mesg->content.normal.flag, - mesg->content.normal.targetless_le_arp); - pr_debug("in l_arp_update\n"); - if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */ - pr_debug("LANE2 3.1.5, got tlvs, size %d\n", - mesg->sizeoftlvs); - lane2_associate_ind(dev, mesg->content.normal.mac_addr, - tmp, mesg->sizeoftlvs); - } - break; - case l_config: - priv->maximum_unknown_frame_count = - mesg->content.config.maximum_unknown_frame_count; - priv->max_unknown_frame_time = - (mesg->content.config.max_unknown_frame_time * HZ); - priv->max_retry_count = mesg->content.config.max_retry_count; - priv->aging_time = (mesg->content.config.aging_time * HZ); - priv->forward_delay_time = - (mesg->content.config.forward_delay_time * HZ); - priv->arp_response_time = - (mesg->content.config.arp_response_time * HZ); - priv->flush_timeout = (mesg->content.config.flush_timeout * HZ); - priv->path_switching_delay = - (mesg->content.config.path_switching_delay * HZ); - priv->lane_version = mesg->content.config.lane_version; - /* LANE2 */ - priv->lane2_ops = NULL; - if (priv->lane_version > 1) - priv->lane2_ops = &lane2_ops; - rtnl_lock(); - if (dev_set_mtu(dev, mesg->content.config.mtu)) - pr_info("%s: change_mtu to %d failed\n", - dev->name, mesg->content.config.mtu); - rtnl_unlock(); - priv->is_proxy = mesg->content.config.is_proxy; - break; - case l_flush_tran_id: - lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr, - mesg->content.normal.flag); - break; - case l_set_lecid: - priv->lecid = - (unsigned short)(0xffff & mesg->content.normal.flag); - break; - case l_should_bridge: -#if IS_ENABLED(CONFIG_BRIDGE) - { - pr_debug("%s: bridge zeppelin asks about %pM\n", - dev->name, mesg->content.proxy.mac_addr); - - if (br_fdb_test_addr_hook == NULL) - break; - - if (br_fdb_test_addr_hook(dev, mesg->content.proxy.mac_addr)) { - /* hit from bridge table, send LE_ARP_RESPONSE */ - struct sk_buff *skb2; - struct sock *sk; - - pr_debug("%s: entry found, responding to zeppelin\n", - dev->name); - skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (skb2 == NULL) - break; - skb2->len = sizeof(struct atmlec_msg); - skb_copy_to_linear_data(skb2, mesg, sizeof(*mesg)); - struct atm_vcc *vcc; - - rcu_read_lock(); - vcc = rcu_dereference(priv->lecd); - if (vcc) { - atm_force_charge(vcc, skb2->truesize); - sk = sk_atm(vcc); - skb_queue_tail(&sk->sk_receive_queue, skb2); - sk->sk_data_ready(sk); - } else { - dev_kfree_skb(skb2); - } - rcu_read_unlock(); - } - } -#endif /* IS_ENABLED(CONFIG_BRIDGE) */ - break; - default: - pr_info("%s: Unknown message type %d\n", dev->name, mesg->type); - dev_kfree_skb(skb); - return -EINVAL; - } - dev_kfree_skb(skb); - return 0; -} - -static void lec_atm_close(struct atm_vcc *vcc) -{ - struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = netdev_priv(dev); - - rcu_assign_pointer(priv->lecd, NULL); - synchronize_rcu(); - /* Do something needful? */ - - netif_stop_queue(dev); - lec_arp_destroy(priv); - - pr_info("%s: Shut down!\n", dev->name); - module_put(THIS_MODULE); -} - -static const struct atmdev_ops lecdev_ops = { - .close = lec_atm_close, - .send = lec_atm_send -}; - -static struct atm_dev lecatm_dev = { - .ops = &lecdev_ops, - .type = "lec", - .number = 999, /* dummy device number */ - .lock = __SPIN_LOCK_UNLOCKED(lecatm_dev.lock) -}; - -/* - * LANE2: new argument struct sk_buff *data contains - * the LE_ARP based TLVs introduced in the LANE2 spec - */ -static int -send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, - const unsigned char *mac_addr, const unsigned char *atm_addr, - struct sk_buff *data) -{ - struct atm_vcc *vcc; - struct sock *sk; - struct sk_buff *skb; - struct atmlec_msg *mesg; - - if (!priv || !rcu_access_pointer(priv->lecd)) - return -1; - - skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); - if (!skb) - return -1; - skb->len = sizeof(struct atmlec_msg); - mesg = (struct atmlec_msg *)skb->data; - memset(mesg, 0, sizeof(struct atmlec_msg)); - mesg->type = type; - if (data != NULL) - mesg->sizeoftlvs = data->len; - if (mac_addr) - ether_addr_copy(mesg->content.normal.mac_addr, mac_addr); - else - mesg->content.normal.targetless_le_arp = 1; - if (atm_addr) - memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); - - rcu_read_lock(); - vcc = rcu_dereference(priv->lecd); - if (!vcc) { - rcu_read_unlock(); - kfree_skb(skb); - return -1; - } - - atm_force_charge(vcc, skb->truesize); - sk = sk_atm(vcc); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - - if (data != NULL) { - pr_debug("about to send %d bytes of data\n", data->len); - atm_force_charge(vcc, data->truesize); - skb_queue_tail(&sk->sk_receive_queue, data); - sk->sk_data_ready(sk); - } - - rcu_read_unlock(); - return 0; -} - -static void lec_set_multicast_list(struct net_device *dev) -{ - /* - * by default, all multicast frames arrive over the bus. - * eventually support selective multicast service - */ -} - -static const struct net_device_ops lec_netdev_ops = { - .ndo_open = lec_open, - .ndo_stop = lec_close, - .ndo_start_xmit = lec_start_xmit, - .ndo_tx_timeout = lec_tx_timeout, - .ndo_set_rx_mode = lec_set_multicast_list, -}; - -static const unsigned char lec_ctrl_magic[] = { - 0xff, - 0x00, - 0x01, - 0x01 -}; - -#define LEC_DATA_DIRECT_8023 2 -#define LEC_DATA_DIRECT_8025 3 - -static int lec_is_data_direct(struct atm_vcc *vcc) -{ - return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) || - (vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025)); -} - -static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) -{ - unsigned long flags; - struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = netdev_priv(dev); - -#if DUMP_PACKETS > 0 - printk(KERN_DEBUG "%s: vcc vpi:%d vci:%d\n", - dev->name, vcc->vpi, vcc->vci); -#endif - if (!skb) { - pr_debug("%s: null skb\n", dev->name); - lec_vcc_close(priv, vcc); - return; - } -#if DUMP_PACKETS >= 2 -#define MAX_SKB_DUMP 99 -#elif DUMP_PACKETS >= 1 -#define MAX_SKB_DUMP 30 -#endif -#if DUMP_PACKETS > 0 - printk(KERN_DEBUG "%s: rcv datalen:%ld lecid:%4.4x\n", - dev->name, skb->len, priv->lecid); - print_hex_dump(KERN_DEBUG, "", DUMP_OFFSET, 16, 1, - skb->data, min(MAX_SKB_DUMP, skb->len), true); -#endif /* DUMP_PACKETS > 0 */ - if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { - /* Control frame, to daemon */ - struct sock *sk = sk_atm(vcc); - - pr_debug("%s: To daemon\n", dev->name); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - } else { /* Data frame, queue to protocol handlers */ - struct lec_arp_table *entry; - unsigned char *src, *dst; - - atm_return(vcc, skb->truesize); - if (*(__be16 *) skb->data == htons(priv->lecid) || - !rcu_access_pointer(priv->lecd) || !(dev->flags & IFF_UP)) { - /* - * Probably looping back, or if lecd is missing, - * lecd has gone down - */ - pr_debug("Ignoring frame...\n"); - dev_kfree_skb(skb); - return; - } - dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest; - - /* - * If this is a Data Direct VCC, and the VCC does not match - * the LE_ARP cache entry, delete the LE_ARP cache entry. - */ - spin_lock_irqsave(&priv->lec_arp_lock, flags); - if (lec_is_data_direct(vcc)) { - src = ((struct lecdatahdr_8023 *)skb->data)->h_source; - entry = lec_arp_find(priv, src); - if (entry && entry->vcc != vcc) { - lec_arp_remove(priv, entry); - lec_arp_put(entry); - } - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - - if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */ - !priv->is_proxy && /* Proxy wants all the packets */ - memcmp(dst, dev->dev_addr, dev->addr_len)) { - dev_kfree_skb(skb); - return; - } - if (!hlist_empty(&priv->lec_arp_empty_ones)) - lec_arp_check_empties(priv, vcc, skb); - skb_pull(skb, 2); /* skip lec_id */ - skb->protocol = eth_type_trans(skb, dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); - netif_rx(skb); - } -} - -static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc); - struct net_device *dev = skb->dev; - - if (vpriv == NULL) { - pr_info("vpriv = NULL!?!?!?\n"); - return; - } - - vpriv->old_pop(vcc, skb); - - if (vpriv->xoff && atm_may_send(vcc, 0)) { - vpriv->xoff = 0; - if (netif_running(dev) && netif_queue_stopped(dev)) - netif_wake_queue(dev); - } -} - -static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) -{ - struct lec_vcc_priv *vpriv; - int bytes_left; - struct atmlec_ioc ioc_data; - - lockdep_assert_held(&lec_mutex); - /* Lecd must be up in this case */ - bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc)); - if (bytes_left != 0) - pr_info("copy from user failed for %d bytes\n", bytes_left); - if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) - return -EINVAL; - ioc_data.dev_num = array_index_nospec(ioc_data.dev_num, MAX_LEC_ITF); - if (!dev_lec[ioc_data.dev_num]) - return -EINVAL; - vpriv = kmalloc_obj(struct lec_vcc_priv); - if (!vpriv) - return -ENOMEM; - vpriv->xoff = 0; - vpriv->old_pop = vcc->pop; - vcc->user_back = vpriv; - vcc->pop = lec_pop; - lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]), - &ioc_data, vcc, vcc->push); - vcc->proto_data = dev_lec[ioc_data.dev_num]; - vcc->push = lec_push; - return 0; -} - -static int lec_mcast_attach(struct atm_vcc *vcc, int arg) -{ - lockdep_assert_held(&lec_mutex); - if (arg < 0 || arg >= MAX_LEC_ITF) - return -EINVAL; - arg = array_index_nospec(arg, MAX_LEC_ITF); - if (!dev_lec[arg]) - return -EINVAL; - vcc->proto_data = dev_lec[arg]; - return lec_mcast_make(netdev_priv(dev_lec[arg]), vcc); -} - -/* Initialize device. */ -static int lecd_attach(struct atm_vcc *vcc, int arg) -{ - int i; - struct lec_priv *priv; - - lockdep_assert_held(&lec_mutex); - if (arg < 0) - arg = 0; - if (arg >= MAX_LEC_ITF) - return -EINVAL; - i = array_index_nospec(arg, MAX_LEC_ITF); - if (!dev_lec[i]) { - int size; - - size = sizeof(struct lec_priv); - dev_lec[i] = alloc_etherdev(size); - if (!dev_lec[i]) - return -ENOMEM; - dev_lec[i]->netdev_ops = &lec_netdev_ops; - dev_lec[i]->max_mtu = 18190; - snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i); - if (register_netdev(dev_lec[i])) { - free_netdev(dev_lec[i]); - dev_lec[i] = NULL; - return -EINVAL; - } - - priv = netdev_priv(dev_lec[i]); - } else { - priv = netdev_priv(dev_lec[i]); - if (rcu_access_pointer(priv->lecd)) - return -EADDRINUSE; - } - lec_arp_init(priv); - priv->itfnum = i; /* LANE2 addition */ - rcu_assign_pointer(priv->lecd, vcc); - vcc->dev = &lecatm_dev; - vcc_insert_socket(sk_atm(vcc)); - - vcc->proto_data = dev_lec[i]; - set_bit(ATM_VF_META, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - /* Set default values to these variables */ - priv->maximum_unknown_frame_count = 1; - priv->max_unknown_frame_time = (1 * HZ); - priv->vcc_timeout_period = (1200 * HZ); - priv->max_retry_count = 1; - priv->aging_time = (300 * HZ); - priv->forward_delay_time = (15 * HZ); - priv->topology_change = 0; - priv->arp_response_time = (1 * HZ); - priv->flush_timeout = (4 * HZ); - priv->path_switching_delay = (6 * HZ); - - if (dev_lec[i]->flags & IFF_UP) - netif_start_queue(dev_lec[i]); - __module_get(THIS_MODULE); - return i; -} - -#ifdef CONFIG_PROC_FS -static const char *lec_arp_get_status_string(unsigned char status) -{ - static const char *const lec_arp_status_string[] = { - "ESI_UNKNOWN ", - "ESI_ARP_PENDING ", - "ESI_VC_PENDING ", - " ", - "ESI_FLUSH_PENDING ", - "ESI_FORWARD_DIRECT" - }; - - if (status > ESI_FORWARD_DIRECT) - status = 3; /* ESI_UNDEFINED */ - return lec_arp_status_string[status]; -} - -static void lec_info(struct seq_file *seq, struct lec_arp_table *entry) -{ - seq_printf(seq, "%pM ", entry->mac_addr); - seq_printf(seq, "%*phN ", ATM_ESA_LEN, entry->atm_addr); - seq_printf(seq, "%s %4.4x", lec_arp_get_status_string(entry->status), - entry->flags & 0xffff); - if (entry->vcc) - seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci); - else - seq_printf(seq, " "); - if (entry->recv_vcc) { - seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi, - entry->recv_vcc->vci); - } - seq_putc(seq, '\n'); -} - -struct lec_state { - unsigned long flags; - struct lec_priv *locked; - struct hlist_node *node; - struct net_device *dev; - int itf; - int arp_table; - int misc_table; -}; - -static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl, - loff_t *l) -{ - struct hlist_node *e = state->node; - - if (!e) - e = tbl->first; - if (e == SEQ_START_TOKEN) { - e = tbl->first; - --*l; - } - - for (; e; e = e->next) { - if (--*l < 0) - break; - } - state->node = e; - - return (*l < 0) ? state : NULL; -} - -static void *lec_arp_walk(struct lec_state *state, loff_t *l, - struct lec_priv *priv) -{ - void *v = NULL; - int p; - - for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) { - v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l); - if (v) - break; - } - state->arp_table = p; - return v; -} - -static void *lec_misc_walk(struct lec_state *state, loff_t *l, - struct lec_priv *priv) -{ - struct hlist_head *lec_misc_tables[] = { - &priv->lec_arp_empty_ones, - &priv->lec_no_forward, - &priv->mcast_fwds - }; - void *v = NULL; - int q; - - for (q = state->misc_table; q < ARRAY_SIZE(lec_misc_tables); q++) { - v = lec_tbl_walk(state, lec_misc_tables[q], l); - if (v) - break; - } - state->misc_table = q; - return v; -} - -static void *lec_priv_walk(struct lec_state *state, loff_t *l, - struct lec_priv *priv) -{ - if (!state->locked) { - state->locked = priv; - spin_lock_irqsave(&priv->lec_arp_lock, state->flags); - } - if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) { - spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags); - state->locked = NULL; - /* Partial state reset for the next time we get called */ - state->arp_table = state->misc_table = 0; - } - return state->locked; -} - -static void *lec_itf_walk(struct lec_state *state, loff_t *l) -{ - struct net_device *dev; - void *v; - - dev = state->dev ? state->dev : dev_lec[state->itf]; - v = (dev && netdev_priv(dev)) ? - lec_priv_walk(state, l, netdev_priv(dev)) : NULL; - if (!v && dev) { - /* Partial state reset for the next time we get called */ - dev = NULL; - } - state->dev = dev; - return v; -} - -static void *lec_get_idx(struct lec_state *state, loff_t l) -{ - void *v = NULL; - - for (; state->itf < MAX_LEC_ITF; state->itf++) { - v = lec_itf_walk(state, &l); - if (v) - break; - } - return v; -} - -static void *lec_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct lec_state *state = seq->private; - - mutex_lock(&lec_mutex); - state->itf = 0; - state->dev = NULL; - state->locked = NULL; - state->arp_table = 0; - state->misc_table = 0; - state->node = SEQ_START_TOKEN; - - return *pos ? lec_get_idx(state, *pos) : SEQ_START_TOKEN; -} - -static void lec_seq_stop(struct seq_file *seq, void *v) -{ - struct lec_state *state = seq->private; - - if (state->dev) { - spin_unlock_irqrestore(&state->locked->lec_arp_lock, - state->flags); - state->dev = NULL; - } - mutex_unlock(&lec_mutex); -} - -static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct lec_state *state = seq->private; - - ++*pos; - return lec_get_idx(state, 1); -} - -static int lec_seq_show(struct seq_file *seq, void *v) -{ - static const char lec_banner[] = - "Itf MAC ATM destination" - " Status Flags " - "VPI/VCI Recv VPI/VCI\n"; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, lec_banner); - else { - struct lec_state *state = seq->private; - struct net_device *dev = state->dev; - struct lec_arp_table *entry = hlist_entry(state->node, - struct lec_arp_table, - next); - - seq_printf(seq, "%s ", dev->name); - lec_info(seq, entry); - } - return 0; -} - -static const struct seq_operations lec_seq_ops = { - .start = lec_seq_start, - .next = lec_seq_next, - .stop = lec_seq_stop, - .show = lec_seq_show, -}; -#endif - -static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct atm_vcc *vcc = ATM_SD(sock); - int err = 0; - - switch (cmd) { - case ATMLEC_CTRL: - case ATMLEC_MCAST: - case ATMLEC_DATA: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; - default: - return -ENOIOCTLCMD; - } - - mutex_lock(&lec_mutex); - switch (cmd) { - case ATMLEC_CTRL: - err = lecd_attach(vcc, (int)arg); - if (err >= 0) - sock->state = SS_CONNECTED; - break; - case ATMLEC_MCAST: - err = lec_mcast_attach(vcc, (int)arg); - break; - case ATMLEC_DATA: - err = lec_vcc_attach(vcc, (void __user *)arg); - break; - } - - mutex_unlock(&lec_mutex); - return err; -} - -static struct atm_ioctl lane_ioctl_ops = { - .owner = THIS_MODULE, - .ioctl = lane_ioctl, -}; - -static int __init lane_module_init(void) -{ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *p; - - p = proc_create_seq_private("lec", 0444, atm_proc_root, &lec_seq_ops, - sizeof(struct lec_state), NULL); - if (!p) { - pr_err("Unable to initialize /proc/net/atm/lec\n"); - return -ENOMEM; - } -#endif - - register_atm_ioctl(&lane_ioctl_ops); - pr_info("lec.c: initialized\n"); - return 0; -} - -static void __exit lane_module_cleanup(void) -{ - int i; - -#ifdef CONFIG_PROC_FS - remove_proc_entry("lec", atm_proc_root); -#endif - - deregister_atm_ioctl(&lane_ioctl_ops); - - for (i = 0; i < MAX_LEC_ITF; i++) { - if (dev_lec[i] != NULL) { - unregister_netdev(dev_lec[i]); - free_netdev(dev_lec[i]); - dev_lec[i] = NULL; - } - } -} - -module_init(lane_module_init); -module_exit(lane_module_cleanup); - -/* - * LANE2: 3.1.3, LE_RESOLVE.request - * Non force allocates memory and fills in *tlvs, fills in *sizeoftlvs. - * If sizeoftlvs == NULL the default TLVs associated with this - * lec will be used. - * If dst_mac == NULL, targetless LE_ARP will be sent - */ -static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force, - u8 **tlvs, u32 *sizeoftlvs) -{ - unsigned long flags; - struct lec_priv *priv = netdev_priv(dev); - struct lec_arp_table *table; - struct sk_buff *skb; - int retval; - - if (force == 0) { - spin_lock_irqsave(&priv->lec_arp_lock, flags); - table = lec_arp_find(priv, dst_mac); - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - if (table == NULL) - return -1; - - *tlvs = kmemdup(table->tlvs, table->sizeoftlvs, GFP_ATOMIC); - if (*tlvs == NULL) - return -1; - - *sizeoftlvs = table->sizeoftlvs; - - return 0; - } - - if (sizeoftlvs == NULL) - retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL); - - else { - skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC); - if (skb == NULL) - return -1; - skb->len = *sizeoftlvs; - skb_copy_to_linear_data(skb, *tlvs, *sizeoftlvs); - retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb); - } - return retval; -} - -/* - * LANE2: 3.1.4, LE_ASSOCIATE.request - * Associate the *tlvs with the *lan_dst address. - * Will overwrite any previous association - * Returns 1 for success, 0 for failure (out of memory) - * - */ -static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, - const u8 *tlvs, u32 sizeoftlvs) -{ - int retval; - struct sk_buff *skb; - struct lec_priv *priv = netdev_priv(dev); - - if (!ether_addr_equal(lan_dst, dev->dev_addr)) - return 0; /* not our mac address */ - - kfree(priv->tlvs); /* NULL if there was no previous association */ - - priv->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL); - if (priv->tlvs == NULL) - return 0; - priv->sizeoftlvs = sizeoftlvs; - - skb = alloc_skb(sizeoftlvs, GFP_ATOMIC); - if (skb == NULL) - return 0; - skb->len = sizeoftlvs; - skb_copy_to_linear_data(skb, tlvs, sizeoftlvs); - retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb); - if (retval != 0) - pr_info("lec.c: lane2_associate_req() failed\n"); - /* - * If the previous association has changed we must - * somehow notify other LANE entities about the change - */ - return 1; -} - -/* - * LANE2: 3.1.5, LE_ASSOCIATE.indication - * - */ -static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, - const u8 *tlvs, u32 sizeoftlvs) -{ -#if 0 - int i = 0; -#endif - struct lec_priv *priv = netdev_priv(dev); -#if 0 /* - * Why have the TLVs in LE_ARP entries - * since we do not use them? When you - * uncomment this code, make sure the - * TLVs get freed when entry is killed - */ - struct lec_arp_table *entry = lec_arp_find(priv, mac_addr); - - if (entry == NULL) - return; /* should not happen */ - - kfree(entry->tlvs); - - entry->tlvs = kmemdup(tlvs, sizeoftlvs, GFP_KERNEL); - if (entry->tlvs == NULL) - return; - entry->sizeoftlvs = sizeoftlvs; -#endif -#if 0 - pr_info("\n"); - pr_info("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs); - while (i < sizeoftlvs) - pr_cont("%02x ", tlvs[i++]); - - pr_cont("\n"); -#endif - - /* tell MPOA about the TLVs we saw */ - if (priv->lane2_ops && priv->lane2_ops->associate_indicator) { - priv->lane2_ops->associate_indicator(dev, mac_addr, - tlvs, sizeoftlvs); - } -} - -/* - * Here starts what used to lec_arpc.c - * - * lec_arpc.c was added here when making - * lane client modular. October 1997 - */ - -#include -#include -#include -#include -#include -#include - -#if 0 -#define pr_debug(format, args...) -/* - #define pr_debug printk -*/ -#endif -#define DEBUG_ARP_TABLE 0 - -#define LEC_ARP_REFRESH_INTERVAL (3*HZ) - -static void lec_arp_check_expire(struct work_struct *work); -static void lec_arp_expire_arp(struct timer_list *t); - -/* - * Arp table funcs - */ - -#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE - 1)) - -/* - * Initialization of arp-cache - */ -static void lec_arp_init(struct lec_priv *priv) -{ - unsigned short i; - - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) - INIT_HLIST_HEAD(&priv->lec_arp_tables[i]); - INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); - INIT_HLIST_HEAD(&priv->lec_no_forward); - INIT_HLIST_HEAD(&priv->mcast_fwds); - spin_lock_init(&priv->lec_arp_lock); - INIT_DELAYED_WORK(&priv->lec_arp_work, lec_arp_check_expire); - schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL); -} - -static void lec_arp_clear_vccs(struct lec_arp_table *entry) -{ - if (entry->vcc) { - struct atm_vcc *vcc = entry->vcc; - struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc); - struct net_device *dev = (struct net_device *)vcc->proto_data; - - if (vpriv) { - vcc->pop = vpriv->old_pop; - if (vpriv->xoff) - netif_wake_queue(dev); - kfree(vpriv); - vcc->user_back = NULL; - vcc->push = entry->old_push; - vcc_release_async(vcc, -EPIPE); - } - entry->vcc = NULL; - } - if (entry->recv_vcc) { - struct atm_vcc *vcc = entry->recv_vcc; - struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc); - - if (vpriv) { - kfree(vpriv); - vcc->user_back = NULL; - - entry->recv_vcc->push = entry->old_recv_push; - vcc_release_async(entry->recv_vcc, -EPIPE); - } - entry->recv_vcc = NULL; - } -} - -/* - * Insert entry to lec_arp_table - * LANE2: Add to the end of the list to satisfy 8.1.13 - */ -static inline void -lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry) -{ - struct hlist_head *tmp; - - tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])]; - hlist_add_head(&entry->next, tmp); - - pr_debug("Added entry:%pM\n", entry->mac_addr); -} - -/* - * Remove entry from lec_arp_table - */ -static int -lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) -{ - struct lec_arp_table *entry; - int i, remove_vcc = 1; - - if (!to_remove) - return -1; - - hlist_del(&to_remove->next); - timer_delete(&to_remove->timer); - - /* - * If this is the only MAC connected to this VCC, - * also tear down the VCC - */ - if (to_remove->status >= ESI_FLUSH_PENDING) { - /* - * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT - */ - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, - &priv->lec_arp_tables[i], next) { - if (memcmp(to_remove->atm_addr, - entry->atm_addr, ATM_ESA_LEN) == 0) { - remove_vcc = 0; - break; - } - } - } - if (remove_vcc) - lec_arp_clear_vccs(to_remove); - } - skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ - - pr_debug("Removed entry:%pM\n", to_remove->mac_addr); - return 0; -} - -#if DEBUG_ARP_TABLE -static const char *get_status_string(unsigned char st) -{ - switch (st) { - case ESI_UNKNOWN: - return "ESI_UNKNOWN"; - case ESI_ARP_PENDING: - return "ESI_ARP_PENDING"; - case ESI_VC_PENDING: - return "ESI_VC_PENDING"; - case ESI_FLUSH_PENDING: - return "ESI_FLUSH_PENDING"; - case ESI_FORWARD_DIRECT: - return "ESI_FORWARD_DIRECT"; - } - return ""; -} - -static void dump_arp_table(struct lec_priv *priv) -{ - struct lec_arp_table *rulla; - char buf[256]; - int i, offset; - - pr_info("Dump %p:\n", priv); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(rulla, - &priv->lec_arp_tables[i], next) { - offset = 0; - offset += sprintf(buf, "%d: %p\n", i, rulla); - offset += sprintf(buf + offset, "Mac: %pM ", - rulla->mac_addr); - offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN, - rulla->atm_addr); - offset += sprintf(buf + offset, - "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", - rulla->vcc ? rulla->vcc->vpi : 0, - rulla->vcc ? rulla->vcc->vci : 0, - rulla->recv_vcc ? rulla->recv_vcc-> - vpi : 0, - rulla->recv_vcc ? rulla->recv_vcc-> - vci : 0, rulla->last_used, - rulla->timestamp, rulla->no_tries); - offset += - sprintf(buf + offset, - "Flags:%x, Packets_flooded:%x, Status: %s ", - rulla->flags, rulla->packets_flooded, - get_status_string(rulla->status)); - pr_info("%s\n", buf); - } - } - - if (!hlist_empty(&priv->lec_no_forward)) - pr_info("No forward\n"); - hlist_for_each_entry(rulla, &priv->lec_no_forward, next) { - offset = 0; - offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr); - offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN, - rulla->atm_addr); - offset += sprintf(buf + offset, - "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", - rulla->vcc ? rulla->vcc->vpi : 0, - rulla->vcc ? rulla->vcc->vci : 0, - rulla->recv_vcc ? rulla->recv_vcc->vpi : 0, - rulla->recv_vcc ? rulla->recv_vcc->vci : 0, - rulla->last_used, - rulla->timestamp, rulla->no_tries); - offset += sprintf(buf + offset, - "Flags:%x, Packets_flooded:%x, Status: %s ", - rulla->flags, rulla->packets_flooded, - get_status_string(rulla->status)); - pr_info("%s\n", buf); - } - - if (!hlist_empty(&priv->lec_arp_empty_ones)) - pr_info("Empty ones\n"); - hlist_for_each_entry(rulla, &priv->lec_arp_empty_ones, next) { - offset = 0; - offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr); - offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN, - rulla->atm_addr); - offset += sprintf(buf + offset, - "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", - rulla->vcc ? rulla->vcc->vpi : 0, - rulla->vcc ? rulla->vcc->vci : 0, - rulla->recv_vcc ? rulla->recv_vcc->vpi : 0, - rulla->recv_vcc ? rulla->recv_vcc->vci : 0, - rulla->last_used, - rulla->timestamp, rulla->no_tries); - offset += sprintf(buf + offset, - "Flags:%x, Packets_flooded:%x, Status: %s ", - rulla->flags, rulla->packets_flooded, - get_status_string(rulla->status)); - pr_info("%s", buf); - } - - if (!hlist_empty(&priv->mcast_fwds)) - pr_info("Multicast Forward VCCs\n"); - hlist_for_each_entry(rulla, &priv->mcast_fwds, next) { - offset = 0; - offset += sprintf(buf + offset, "Mac: %pM ", rulla->mac_addr); - offset += sprintf(buf + offset, "Atm: %*ph ", ATM_ESA_LEN, - rulla->atm_addr); - offset += sprintf(buf + offset, - "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ", - rulla->vcc ? rulla->vcc->vpi : 0, - rulla->vcc ? rulla->vcc->vci : 0, - rulla->recv_vcc ? rulla->recv_vcc->vpi : 0, - rulla->recv_vcc ? rulla->recv_vcc->vci : 0, - rulla->last_used, - rulla->timestamp, rulla->no_tries); - offset += sprintf(buf + offset, - "Flags:%x, Packets_flooded:%x, Status: %s ", - rulla->flags, rulla->packets_flooded, - get_status_string(rulla->status)); - pr_info("%s\n", buf); - } - -} -#else -#define dump_arp_table(priv) do { } while (0) -#endif - -/* - * Destruction of arp-cache - */ -static void lec_arp_destroy(struct lec_priv *priv) -{ - unsigned long flags; - struct hlist_node *next; - struct lec_arp_table *entry; - int i; - - cancel_delayed_work_sync(&priv->lec_arp_work); - - /* - * Remove all entries - */ - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_tables[i], next) { - lec_arp_remove(priv, entry); - lec_arp_put(entry); - } - INIT_HLIST_HEAD(&priv->lec_arp_tables[i]); - } - - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_empty_ones, next) { - timer_delete_sync(&entry->timer); - lec_arp_clear_vccs(entry); - hlist_del(&entry->next); - lec_arp_put(entry); - } - INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); - - hlist_for_each_entry_safe(entry, next, - &priv->lec_no_forward, next) { - timer_delete_sync(&entry->timer); - lec_arp_clear_vccs(entry); - hlist_del(&entry->next); - lec_arp_put(entry); - } - INIT_HLIST_HEAD(&priv->lec_no_forward); - - hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) { - /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ - lec_arp_clear_vccs(entry); - hlist_del(&entry->next); - lec_arp_put(entry); - } - INIT_HLIST_HEAD(&priv->mcast_fwds); - priv->mcast_vcc = NULL; - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); -} - -/* - * Find entry by mac_address - */ -static struct lec_arp_table *lec_arp_find(struct lec_priv *priv, - const unsigned char *mac_addr) -{ - struct hlist_head *head; - struct lec_arp_table *entry; - - pr_debug("%pM\n", mac_addr); - - head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])]; - hlist_for_each_entry(entry, head, next) { - if (ether_addr_equal(mac_addr, entry->mac_addr)) - return entry; - } - return NULL; -} - -static struct lec_arp_table *make_entry(struct lec_priv *priv, - const unsigned char *mac_addr) -{ - struct lec_arp_table *to_return; - - to_return = kzalloc_obj(struct lec_arp_table, GFP_ATOMIC); - if (!to_return) - return NULL; - ether_addr_copy(to_return->mac_addr, mac_addr); - INIT_HLIST_NODE(&to_return->next); - timer_setup(&to_return->timer, lec_arp_expire_arp, 0); - to_return->last_used = jiffies; - to_return->priv = priv; - skb_queue_head_init(&to_return->tx_wait); - refcount_set(&to_return->usage, 1); - return to_return; -} - -/* Arp sent timer expired */ -static void lec_arp_expire_arp(struct timer_list *t) -{ - struct lec_arp_table *entry; - - entry = timer_container_of(entry, t, timer); - - pr_debug("\n"); - if (entry->status == ESI_ARP_PENDING) { - if (entry->no_tries <= entry->priv->max_retry_count) { - if (entry->is_rdesc) - send_to_lecd(entry->priv, l_rdesc_arp_xmt, - entry->mac_addr, NULL, NULL); - else - send_to_lecd(entry->priv, l_arp_xmt, - entry->mac_addr, NULL, NULL); - entry->no_tries++; - } - mod_timer(&entry->timer, jiffies + (1 * HZ)); - } -} - -/* Unknown/unused vcc expire, remove associated entry */ -static void lec_arp_expire_vcc(struct timer_list *t) -{ - unsigned long flags; - struct lec_arp_table *to_remove = timer_container_of(to_remove, t, - timer); - struct lec_priv *priv = to_remove->priv; - - timer_delete(&to_remove->timer); - - pr_debug("%p %p: vpi:%d vci:%d\n", - to_remove, priv, - to_remove->vcc ? to_remove->recv_vcc->vpi : 0, - to_remove->vcc ? to_remove->recv_vcc->vci : 0); - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - hlist_del(&to_remove->next); - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - - lec_arp_clear_vccs(to_remove); - lec_arp_put(to_remove); -} - -static bool __lec_arp_check_expire(struct lec_arp_table *entry, - unsigned long now, - struct lec_priv *priv) -{ - unsigned long time_to_check; - - if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change) - time_to_check = priv->forward_delay_time; - else - time_to_check = priv->aging_time; - - pr_debug("About to expire: %lx - %lx > %lx\n", - now, entry->last_used, time_to_check); - if (time_after(now, entry->last_used + time_to_check) && - !(entry->flags & LEC_PERMANENT_FLAG) && - !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */ - /* Remove entry */ - pr_debug("Entry timed out\n"); - lec_arp_remove(priv, entry); - lec_arp_put(entry); - } else { - /* Something else */ - if ((entry->status == ESI_VC_PENDING || - entry->status == ESI_ARP_PENDING) && - time_after_eq(now, entry->timestamp + - priv->max_unknown_frame_time)) { - entry->timestamp = jiffies; - entry->packets_flooded = 0; - if (entry->status == ESI_VC_PENDING) - send_to_lecd(priv, l_svc_setup, - entry->mac_addr, - entry->atm_addr, - NULL); - } - if (entry->status == ESI_FLUSH_PENDING && - time_after_eq(now, entry->timestamp + - priv->path_switching_delay)) { - lec_arp_hold(entry); - return true; - } - } - - return false; -} -/* - * Expire entries. - * 1. Re-set timer - * 2. For each entry, delete entries that have aged past the age limit. - * 3. For each entry, depending on the status of the entry, perform - * the following maintenance. - * a. If status is ESI_VC_PENDING or ESI_ARP_PENDING then if the - * tick_count is above the max_unknown_frame_time, clear - * the tick_count to zero and clear the packets_flooded counter - * to zero. This supports the packet rate limit per address - * while flooding unknowns. - * b. If the status is ESI_FLUSH_PENDING and the tick_count is greater - * than or equal to the path_switching_delay, change the status - * to ESI_FORWARD_DIRECT. This causes the flush period to end - * regardless of the progress of the flush protocol. - */ -static void lec_arp_check_expire(struct work_struct *work) -{ - unsigned long flags; - struct lec_priv *priv = - container_of(work, struct lec_priv, lec_arp_work.work); - struct hlist_node *next; - struct lec_arp_table *entry; - unsigned long now; - int i; - - pr_debug("%p\n", priv); - now = jiffies; -restart: - spin_lock_irqsave(&priv->lec_arp_lock, flags); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_tables[i], next) { - if (__lec_arp_check_expire(entry, now, priv)) { - struct sk_buff *skb; - struct atm_vcc *vcc = entry->vcc; - - spin_unlock_irqrestore(&priv->lec_arp_lock, - flags); - while ((skb = skb_dequeue(&entry->tx_wait))) - lec_send(vcc, skb); - entry->last_used = jiffies; - entry->status = ESI_FORWARD_DIRECT; - lec_arp_put(entry); - - goto restart; - } - } - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - - schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL); -} - -/* - * Try to find vcc where mac_address is attached. - * - */ -static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv, - const unsigned char *mac_to_find, - int is_rdesc, - struct lec_arp_table **ret_entry) -{ - unsigned long flags; - struct lec_arp_table *entry; - struct atm_vcc *found; - - if (mac_to_find[0] & 0x01) { - switch (priv->lane_version) { - case 1: - return priv->mcast_vcc; - case 2: /* LANE2 wants arp for multicast addresses */ - if (ether_addr_equal(mac_to_find, bus_mac)) - return priv->mcast_vcc; - break; - default: - break; - } - } - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - entry = lec_arp_find(priv, mac_to_find); - - if (entry) { - if (entry->status == ESI_FORWARD_DIRECT) { - /* Connection Ok */ - entry->last_used = jiffies; - lec_arp_hold(entry); - *ret_entry = entry; - found = entry->vcc; - goto out; - } - /* - * If the LE_ARP cache entry is still pending, reset count to 0 - * so another LE_ARP request can be made for this frame. - */ - if (entry->status == ESI_ARP_PENDING) - entry->no_tries = 0; - /* - * Data direct VC not yet set up, check to see if the unknown - * frame count is greater than the limit. If the limit has - * not been reached, allow the caller to send packet to - * BUS. - */ - if (entry->status != ESI_FLUSH_PENDING && - entry->packets_flooded < - priv->maximum_unknown_frame_count) { - entry->packets_flooded++; - pr_debug("Flooding..\n"); - found = priv->mcast_vcc; - goto out; - } - /* - * We got here because entry->status == ESI_FLUSH_PENDING - * or BUS flood limit was reached for an entry which is - * in ESI_ARP_PENDING or ESI_VC_PENDING state. - */ - lec_arp_hold(entry); - *ret_entry = entry; - pr_debug("entry->status %d entry->vcc %p\n", entry->status, - entry->vcc); - found = NULL; - } else { - /* No matching entry was found */ - entry = make_entry(priv, mac_to_find); - pr_debug("Making entry\n"); - if (!entry) { - found = priv->mcast_vcc; - goto out; - } - lec_arp_add(priv, entry); - /* We want arp-request(s) to be sent */ - entry->packets_flooded = 1; - entry->status = ESI_ARP_PENDING; - entry->no_tries = 1; - entry->last_used = entry->timestamp = jiffies; - entry->is_rdesc = is_rdesc; - if (entry->is_rdesc) - send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, - NULL); - else - send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL); - entry->timer.expires = jiffies + (1 * HZ); - entry->timer.function = lec_arp_expire_arp; - add_timer(&entry->timer); - found = priv->mcast_vcc; - } - -out: - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - return found; -} - -static int -lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr, - unsigned long permanent) -{ - unsigned long flags; - struct hlist_node *next; - struct lec_arp_table *entry; - int i; - - pr_debug("\n"); - spin_lock_irqsave(&priv->lec_arp_lock, flags); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_tables[i], next) { - if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) && - (permanent || - !(entry->flags & LEC_PERMANENT_FLAG))) { - lec_arp_remove(priv, entry); - lec_arp_put(entry); - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - return 0; - } - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - return -1; -} - -/* - * Notifies: Response to arp_request (atm_addr != NULL) - */ -static void -lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr, - const unsigned char *atm_addr, unsigned long remoteflag, - unsigned int targetless_le_arp) -{ - unsigned long flags; - struct hlist_node *next; - struct lec_arp_table *entry, *tmp; - int i; - - pr_debug("%smac:%pM\n", - (targetless_le_arp) ? "targetless " : "", mac_addr); - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - entry = lec_arp_find(priv, mac_addr); - if (entry == NULL && targetless_le_arp) - goto out; /* - * LANE2: ignore targetless LE_ARPs for which - * we have no entry in the cache. 7.1.30 - */ - if (!hlist_empty(&priv->lec_arp_empty_ones)) { - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_empty_ones, next) { - if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) { - hlist_del(&entry->next); - timer_delete(&entry->timer); - tmp = lec_arp_find(priv, mac_addr); - if (tmp) { - timer_delete(&tmp->timer); - tmp->status = ESI_FORWARD_DIRECT; - memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN); - tmp->vcc = entry->vcc; - tmp->old_push = entry->old_push; - tmp->last_used = jiffies; - timer_delete(&entry->timer); - lec_arp_put(entry); - entry = tmp; - } else { - entry->status = ESI_FORWARD_DIRECT; - ether_addr_copy(entry->mac_addr, - mac_addr); - entry->last_used = jiffies; - lec_arp_add(priv, entry); - } - if (remoteflag) - entry->flags |= LEC_REMOTE_FLAG; - else - entry->flags &= ~LEC_REMOTE_FLAG; - pr_debug("After update\n"); - dump_arp_table(priv); - goto out; - } - } - } - - entry = lec_arp_find(priv, mac_addr); - if (!entry) { - entry = make_entry(priv, mac_addr); - if (!entry) - goto out; - entry->status = ESI_UNKNOWN; - lec_arp_add(priv, entry); - /* Temporary, changes before end of function */ - } - memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); - timer_delete(&entry->timer); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(tmp, - &priv->lec_arp_tables[i], next) { - if (entry != tmp && - !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) { - /* Vcc to this host exists */ - if (tmp->status > ESI_VC_PENDING) { - /* - * ESI_FLUSH_PENDING, - * ESI_FORWARD_DIRECT - */ - entry->vcc = tmp->vcc; - entry->old_push = tmp->old_push; - } - entry->status = tmp->status; - break; - } - } - } - if (remoteflag) - entry->flags |= LEC_REMOTE_FLAG; - else - entry->flags &= ~LEC_REMOTE_FLAG; - if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) { - entry->status = ESI_VC_PENDING; - send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL); - } - pr_debug("After update2\n"); - dump_arp_table(priv); -out: - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); -} - -/* - * Notifies: Vcc setup ready - */ -static void -lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data, - struct atm_vcc *vcc, - void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb)) -{ - unsigned long flags; - struct lec_arp_table *entry; - int i, found_entry = 0; - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ - if (ioc_data->receive == 2) { - pr_debug("LEC_ARP: Attaching mcast forward\n"); -#if 0 - entry = lec_arp_find(priv, bus_mac); - if (!entry) { - pr_info("LEC_ARP: Multicast entry not found!\n"); - goto out; - } - memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); - entry->recv_vcc = vcc; - entry->old_recv_push = old_push; -#endif - entry = make_entry(priv, bus_mac); - if (entry == NULL) - goto out; - timer_delete(&entry->timer); - memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); - entry->recv_vcc = vcc; - entry->old_recv_push = old_push; - hlist_add_head(&entry->next, &priv->mcast_fwds); - goto out; - } else if (ioc_data->receive == 1) { - /* - * Vcc which we don't want to make default vcc, - * attach it anyway. - */ - pr_debug("LEC_ARP:Attaching data direct, not default: %*phN\n", - ATM_ESA_LEN, ioc_data->atm_addr); - entry = make_entry(priv, bus_mac); - if (entry == NULL) - goto out; - memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); - eth_zero_addr(entry->mac_addr); - entry->recv_vcc = vcc; - entry->old_recv_push = old_push; - entry->status = ESI_UNKNOWN; - entry->timer.expires = jiffies + priv->vcc_timeout_period; - entry->timer.function = lec_arp_expire_vcc; - hlist_add_head(&entry->next, &priv->lec_no_forward); - add_timer(&entry->timer); - dump_arp_table(priv); - goto out; - } - pr_debug("LEC_ARP:Attaching data direct, default: %*phN\n", - ATM_ESA_LEN, ioc_data->atm_addr); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, - &priv->lec_arp_tables[i], next) { - if (memcmp - (ioc_data->atm_addr, entry->atm_addr, - ATM_ESA_LEN) == 0) { - pr_debug("LEC_ARP: Attaching data direct\n"); - pr_debug("Currently -> Vcc: %d, Rvcc:%d\n", - entry->vcc ? entry->vcc->vci : 0, - entry->recv_vcc ? entry->recv_vcc-> - vci : 0); - found_entry = 1; - timer_delete(&entry->timer); - entry->vcc = vcc; - entry->old_push = old_push; - if (entry->status == ESI_VC_PENDING) { - if (priv->maximum_unknown_frame_count - == 0) - entry->status = - ESI_FORWARD_DIRECT; - else { - entry->timestamp = jiffies; - entry->status = - ESI_FLUSH_PENDING; -#if 0 - send_to_lecd(priv, l_flush_xmt, - NULL, - entry->atm_addr, - NULL); -#endif - } - } else { - /* - * They were forming a connection - * to us, and we to them. Our - * ATM address is numerically lower - * than theirs, so we make connection - * we formed into default VCC (8.1.11). - * Connection they made gets torn - * down. This might confuse some - * clients. Can be changed if - * someone reports trouble... - */ - ; - } - } - } - } - if (found_entry) { - pr_debug("After vcc was added\n"); - dump_arp_table(priv); - goto out; - } - /* - * Not found, snatch address from first data packet that arrives - * from this vcc - */ - entry = make_entry(priv, bus_mac); - if (!entry) - goto out; - entry->vcc = vcc; - entry->old_push = old_push; - memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); - eth_zero_addr(entry->mac_addr); - entry->status = ESI_UNKNOWN; - hlist_add_head(&entry->next, &priv->lec_arp_empty_ones); - entry->timer.expires = jiffies + priv->vcc_timeout_period; - entry->timer.function = lec_arp_expire_vcc; - add_timer(&entry->timer); - pr_debug("After vcc was added\n"); - dump_arp_table(priv); -out: - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); -} - -static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) -{ - unsigned long flags; - struct lec_arp_table *entry; - int i; - - pr_debug("%lx\n", tran_id); -restart: - spin_lock_irqsave(&priv->lec_arp_lock, flags); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry(entry, - &priv->lec_arp_tables[i], next) { - if (entry->flush_tran_id == tran_id && - entry->status == ESI_FLUSH_PENDING) { - struct sk_buff *skb; - struct atm_vcc *vcc = entry->vcc; - - lec_arp_hold(entry); - spin_unlock_irqrestore(&priv->lec_arp_lock, - flags); - while ((skb = skb_dequeue(&entry->tx_wait))) - lec_send(vcc, skb); - entry->last_used = jiffies; - entry->status = ESI_FORWARD_DIRECT; - lec_arp_put(entry); - pr_debug("LEC_ARP: Flushed\n"); - goto restart; - } - } - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - dump_arp_table(priv); -} - -static void -lec_set_flush_tran_id(struct lec_priv *priv, - const unsigned char *atm_addr, unsigned long tran_id) -{ - unsigned long flags; - struct lec_arp_table *entry; - int i; - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) - hlist_for_each_entry(entry, - &priv->lec_arp_tables[i], next) { - if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) { - entry->flush_tran_id = tran_id; - pr_debug("Set flush transaction id to %lx for %p\n", - tran_id, entry); - } - } - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); -} - -static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) -{ - unsigned long flags; - unsigned char mac_addr[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; - struct lec_arp_table *to_add; - struct lec_vcc_priv *vpriv; - int err = 0; - - vpriv = kmalloc_obj(struct lec_vcc_priv); - if (!vpriv) - return -ENOMEM; - vpriv->xoff = 0; - vpriv->old_pop = vcc->pop; - vcc->user_back = vpriv; - vcc->pop = lec_pop; - spin_lock_irqsave(&priv->lec_arp_lock, flags); - to_add = make_entry(priv, mac_addr); - if (!to_add) { - vcc->pop = vpriv->old_pop; - kfree(vpriv); - err = -ENOMEM; - goto out; - } - memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN); - to_add->status = ESI_FORWARD_DIRECT; - to_add->flags |= LEC_PERMANENT_FLAG; - to_add->vcc = vcc; - to_add->old_push = vcc->push; - vcc->push = lec_push; - priv->mcast_vcc = vcc; - lec_arp_add(priv, to_add); -out: - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - return err; -} - -static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) -{ - unsigned long flags; - struct hlist_node *next; - struct lec_arp_table *entry; - int i; - - pr_debug("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci); - dump_arp_table(priv); - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - - for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_tables[i], next) { - if (vcc == entry->vcc) { - lec_arp_remove(priv, entry); - lec_arp_put(entry); - if (priv->mcast_vcc == vcc) - priv->mcast_vcc = NULL; - } - } - } - - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_empty_ones, next) { - if (entry->vcc == vcc) { - lec_arp_clear_vccs(entry); - timer_delete(&entry->timer); - hlist_del(&entry->next); - lec_arp_put(entry); - } - } - - hlist_for_each_entry_safe(entry, next, - &priv->lec_no_forward, next) { - if (entry->recv_vcc == vcc) { - lec_arp_clear_vccs(entry); - timer_delete(&entry->timer); - hlist_del(&entry->next); - lec_arp_put(entry); - } - } - - hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) { - if (entry->recv_vcc == vcc) { - lec_arp_clear_vccs(entry); - /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ - hlist_del(&entry->next); - lec_arp_put(entry); - } - } - - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); - dump_arp_table(priv); -} - -static void -lec_arp_check_empties(struct lec_priv *priv, - struct atm_vcc *vcc, struct sk_buff *skb) -{ - unsigned long flags; - struct hlist_node *next; - struct lec_arp_table *entry, *tmp; - struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data; - unsigned char *src = hdr->h_source; - - spin_lock_irqsave(&priv->lec_arp_lock, flags); - hlist_for_each_entry_safe(entry, next, - &priv->lec_arp_empty_ones, next) { - if (vcc == entry->vcc) { - timer_delete(&entry->timer); - ether_addr_copy(entry->mac_addr, src); - entry->status = ESI_FORWARD_DIRECT; - entry->last_used = jiffies; - /* We might have got an entry */ - tmp = lec_arp_find(priv, src); - if (tmp) { - lec_arp_remove(priv, tmp); - lec_arp_put(tmp); - } - hlist_del(&entry->next); - lec_arp_add(priv, entry); - goto out; - } - } - pr_debug("LEC_ARP: Arp_check_empties: entry not found!\n"); -out: - spin_unlock_irqrestore(&priv->lec_arp_lock, flags); -} - -MODULE_DESCRIPTION("ATM LAN Emulation (LANE) support"); -MODULE_LICENSE("GPL"); diff --git a/net/atm/mpc.c b/net/atm/mpc.c deleted file mode 100644 index ce8e9780373b..000000000000 --- a/net/atm/mpc.c +++ /dev/null @@ -1,1538 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* We are an ethernet device */ -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for ip_fast_csum() */ -#include -#include -#include - -/* And atm device */ -#include -#include -#include -/* Modular too */ -#include - -#include "lec.h" -#include "mpc.h" -#include "resources.h" - -/* - * mpc.c: Implementation of MPOA client kernel part - */ - -#if 0 -#define dprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args) -#define dprintk_cont(format, args...) printk(KERN_CONT format, ##args) -#else -#define dprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\ - } while (0) -#define dprintk_cont(format, args...) \ - do { if (0) printk(KERN_CONT format, ##args); } while (0) -#endif - -#if 0 -#define ddprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args) -#define ddprintk_cont(format, args...) printk(KERN_CONT format, ##args) -#else -#define ddprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __func__, ##args);\ - } while (0) -#define ddprintk_cont(format, args...) \ - do { if (0) printk(KERN_CONT format, ##args); } while (0) -#endif - -/* mpc_daemon -> kernel */ -static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc); -static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); -static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); -static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc); -static void mps_death(struct k_message *msg, struct mpoa_client *mpc); -static void clean_up(struct k_message *msg, struct mpoa_client *mpc, - int action); -static void MPOA_cache_impos_rcvd(struct k_message *msg, - struct mpoa_client *mpc); -static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, - struct mpoa_client *mpc); -static void set_mps_mac_addr_rcvd(struct k_message *mesg, - struct mpoa_client *mpc); - -static const uint8_t *copy_macs(struct mpoa_client *mpc, - const uint8_t *router_mac, - const uint8_t *tlvs, uint8_t mps_macs, - uint8_t device_type); -static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry); - -static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc); -static void mpoad_close(struct atm_vcc *vcc); -static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb); - -static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb); -static netdev_tx_t mpc_send_packet(struct sk_buff *skb, - struct net_device *dev); -static int mpoa_event_listener(struct notifier_block *mpoa_notifier, - unsigned long event, void *dev); -static void mpc_timer_refresh(void); -static void mpc_cache_check(struct timer_list *unused); - -static struct llc_snap_hdr llc_snap_mpoa_ctrl = { - 0xaa, 0xaa, 0x03, - {0x00, 0x00, 0x5e}, - {0x00, 0x03} /* For MPOA control PDUs */ -}; -static struct llc_snap_hdr llc_snap_mpoa_data = { - 0xaa, 0xaa, 0x03, - {0x00, 0x00, 0x00}, - {0x08, 0x00} /* This is for IP PDUs only */ -}; -static struct llc_snap_hdr llc_snap_mpoa_data_tagged = { - 0xaa, 0xaa, 0x03, - {0x00, 0x00, 0x00}, - {0x88, 0x4c} /* This is for tagged data PDUs */ -}; - -static struct notifier_block mpoa_notifier = { - mpoa_event_listener, - NULL, - 0 -}; - -struct mpoa_client *mpcs = NULL; /* FIXME */ -static struct atm_mpoa_qos *qos_head = NULL; -static DEFINE_TIMER(mpc_timer, mpc_cache_check); - - -static struct mpoa_client *find_mpc_by_itfnum(int itf) -{ - struct mpoa_client *mpc; - - mpc = mpcs; /* our global linked list */ - while (mpc != NULL) { - if (mpc->dev_num == itf) - return mpc; - mpc = mpc->next; - } - - return NULL; /* not found */ -} - -static struct mpoa_client *find_mpc_by_vcc(struct atm_vcc *vcc) -{ - struct mpoa_client *mpc; - - mpc = mpcs; /* our global linked list */ - while (mpc != NULL) { - if (mpc->mpoad_vcc == vcc) - return mpc; - mpc = mpc->next; - } - - return NULL; /* not found */ -} - -static struct mpoa_client *find_mpc_by_lec(struct net_device *dev) -{ - struct mpoa_client *mpc; - - mpc = mpcs; /* our global linked list */ - while (mpc != NULL) { - if (mpc->dev == dev) - return mpc; - mpc = mpc->next; - } - - return NULL; /* not found */ -} - -/* - * Functions for managing QoS list - */ - -/* - * Overwrites the old entry or makes a new one. - */ -struct atm_mpoa_qos *atm_mpoa_add_qos(__be32 dst_ip, struct atm_qos *qos) -{ - struct atm_mpoa_qos *entry; - - entry = atm_mpoa_search_qos(dst_ip); - if (entry != NULL) { - entry->qos = *qos; - return entry; - } - - entry = kmalloc_obj(struct atm_mpoa_qos); - if (entry == NULL) { - pr_info("mpoa: out of memory\n"); - return entry; - } - - entry->ipaddr = dst_ip; - entry->qos = *qos; - - entry->next = qos_head; - qos_head = entry; - - return entry; -} - -struct atm_mpoa_qos *atm_mpoa_search_qos(__be32 dst_ip) -{ - struct atm_mpoa_qos *qos; - - qos = qos_head; - while (qos) { - if (qos->ipaddr == dst_ip) - break; - qos = qos->next; - } - - return qos; -} - -/* - * Returns 0 for failure - */ -int atm_mpoa_delete_qos(struct atm_mpoa_qos *entry) -{ - struct atm_mpoa_qos *curr; - - if (entry == NULL) - return 0; - if (entry == qos_head) { - qos_head = qos_head->next; - kfree(entry); - return 1; - } - - curr = qos_head; - while (curr != NULL) { - if (curr->next == entry) { - curr->next = entry->next; - kfree(entry); - return 1; - } - curr = curr->next; - } - - return 0; -} - -/* this is buggered - we need locking for qos_head */ -void atm_mpoa_disp_qos(struct seq_file *m) -{ - struct atm_mpoa_qos *qos; - - qos = qos_head; - seq_printf(m, "QoS entries for shortcuts:\n"); - seq_printf(m, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n"); - - while (qos != NULL) { - seq_printf(m, "%pI4\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", - &qos->ipaddr, - qos->qos.txtp.max_pcr, - qos->qos.txtp.pcr, - qos->qos.txtp.min_pcr, - qos->qos.txtp.max_cdv, - qos->qos.txtp.max_sdu, - qos->qos.rxtp.max_pcr, - qos->qos.rxtp.pcr, - qos->qos.rxtp.min_pcr, - qos->qos.rxtp.max_cdv, - qos->qos.rxtp.max_sdu); - qos = qos->next; - } -} - -static struct net_device *find_lec_by_itfnum(int itf) -{ - struct net_device *dev; - char name[IFNAMSIZ]; - - sprintf(name, "lec%d", itf); - dev = dev_get_by_name(&init_net, name); - - return dev; -} - -static struct mpoa_client *alloc_mpc(void) -{ - struct mpoa_client *mpc; - - mpc = kzalloc_obj(struct mpoa_client); - if (mpc == NULL) - return NULL; - rwlock_init(&mpc->ingress_lock); - rwlock_init(&mpc->egress_lock); - mpc->next = mpcs; - atm_mpoa_init_cache(mpc); - - mpc->parameters.mpc_p1 = MPC_P1; - mpc->parameters.mpc_p2 = MPC_P2; - memset(mpc->parameters.mpc_p3, 0, sizeof(mpc->parameters.mpc_p3)); - mpc->parameters.mpc_p4 = MPC_P4; - mpc->parameters.mpc_p5 = MPC_P5; - mpc->parameters.mpc_p6 = MPC_P6; - - mpcs = mpc; - - return mpc; -} - -/* - * - * start_mpc() puts the MPC on line. All the packets destined - * to the lec underneath us are now being monitored and - * shortcuts will be established. - * - */ -static void start_mpc(struct mpoa_client *mpc, struct net_device *dev) -{ - - dprintk("(%s)\n", mpc->dev->name); - if (!dev->netdev_ops) - pr_info("(%s) not starting\n", dev->name); - else { - mpc->old_ops = dev->netdev_ops; - mpc->new_ops = *mpc->old_ops; - mpc->new_ops.ndo_start_xmit = mpc_send_packet; - dev->netdev_ops = &mpc->new_ops; - } -} - -static void stop_mpc(struct mpoa_client *mpc) -{ - struct net_device *dev = mpc->dev; - dprintk("(%s)", mpc->dev->name); - - /* Lets not nullify lec device's dev->hard_start_xmit */ - if (dev->netdev_ops != &mpc->new_ops) { - dprintk_cont(" mpc already stopped, not fatal\n"); - return; - } - dprintk_cont("\n"); - - dev->netdev_ops = mpc->old_ops; - mpc->old_ops = NULL; - - /* close_shortcuts(mpc); ??? FIXME */ -} - -static const char *mpoa_device_type_string(char type) __attribute__ ((unused)); - -static const char *mpoa_device_type_string(char type) -{ - switch (type) { - case NON_MPOA: - return "non-MPOA device"; - case MPS: - return "MPS"; - case MPC: - return "MPC"; - case MPS_AND_MPC: - return "both MPS and MPC"; - } - - return "unspecified (non-MPOA) device"; -} - -/* - * lec device calls this via its netdev_priv(dev)->lane2_ops - * ->associate_indicator() when it sees a TLV in LE_ARP packet. - * We fill in the pointer above when we see a LANE2 lec initializing - * See LANE2 spec 3.1.5 - * - * Quite a big and ugly function but when you look at it - * all it does is to try to locate and parse MPOA Device - * Type TLV. - * We give our lec a pointer to this function and when the - * lec sees a TLV it uses the pointer to call this function. - * - */ -static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr, - const u8 *tlvs, u32 sizeoftlvs) -{ - uint32_t type; - uint8_t length, mpoa_device_type, number_of_mps_macs; - const uint8_t *end_of_tlvs; - struct mpoa_client *mpc; - - mpoa_device_type = number_of_mps_macs = 0; /* silence gcc */ - dprintk("(%s) received TLV(s), ", dev->name); - dprintk("total length of all TLVs %d\n", sizeoftlvs); - mpc = find_mpc_by_lec(dev); /* Sampo-Fix: moved here from below */ - if (mpc == NULL) { - pr_info("(%s) no mpc\n", dev->name); - return; - } - end_of_tlvs = tlvs + sizeoftlvs; - while (end_of_tlvs - tlvs >= 5) { - type = ((tlvs[0] << 24) | (tlvs[1] << 16) | - (tlvs[2] << 8) | tlvs[3]); - length = tlvs[4]; - tlvs += 5; - dprintk(" type 0x%x length %02x\n", type, length); - if (tlvs + length > end_of_tlvs) { - pr_info("TLV value extends past its buffer, aborting parse\n"); - return; - } - - if (type == 0) { - pr_info("mpoa: (%s) TLV type was 0, returning\n", - dev->name); - return; - } - - if (type != TLV_MPOA_DEVICE_TYPE) { - tlvs += length; - continue; /* skip other TLVs */ - } - mpoa_device_type = *tlvs++; - number_of_mps_macs = *tlvs++; - dprintk("(%s) MPOA device type '%s', ", - dev->name, mpoa_device_type_string(mpoa_device_type)); - if (mpoa_device_type == MPS_AND_MPC && - length < (42 + number_of_mps_macs*ETH_ALEN)) { /* :) */ - pr_info("(%s) short MPOA Device Type TLV\n", - dev->name); - continue; - } - if ((mpoa_device_type == MPS || mpoa_device_type == MPC) && - length < 22 + number_of_mps_macs*ETH_ALEN) { - pr_info("(%s) short MPOA Device Type TLV\n", dev->name); - continue; - } - if (mpoa_device_type != MPS && - mpoa_device_type != MPS_AND_MPC) { - dprintk("ignoring non-MPS device "); - if (mpoa_device_type == MPC) - tlvs += 20; - continue; /* we are only interested in MPSs */ - } - if (number_of_mps_macs == 0 && - mpoa_device_type == MPS_AND_MPC) { - pr_info("(%s) MPS_AND_MPC has zero MACs\n", dev->name); - continue; /* someone should read the spec */ - } - dprintk_cont("this MPS has %d MAC addresses\n", - number_of_mps_macs); - - /* - * ok, now we can go and tell our daemon - * the control address of MPS - */ - send_set_mps_ctrl_addr(tlvs, mpc); - - tlvs = copy_macs(mpc, mac_addr, tlvs, - number_of_mps_macs, mpoa_device_type); - if (tlvs == NULL) - return; - } - if (end_of_tlvs - tlvs != 0) - pr_info("(%s) ignoring %zd bytes of trailing TLV garbage\n", - dev->name, end_of_tlvs - tlvs); -} - -/* - * Store at least advertizing router's MAC address - * plus the possible MAC address(es) to mpc->mps_macs. - * For a freshly allocated MPOA client mpc->mps_macs == 0. - */ -static const uint8_t *copy_macs(struct mpoa_client *mpc, - const uint8_t *router_mac, - const uint8_t *tlvs, uint8_t mps_macs, - uint8_t device_type) -{ - int num_macs; - num_macs = (mps_macs > 1) ? mps_macs : 1; - - if (mpc->number_of_mps_macs != num_macs) { /* need to reallocate? */ - if (mpc->number_of_mps_macs != 0) - kfree(mpc->mps_macs); - mpc->number_of_mps_macs = 0; - mpc->mps_macs = kmalloc_array(ETH_ALEN, num_macs, GFP_KERNEL); - if (mpc->mps_macs == NULL) { - pr_info("(%s) out of mem\n", mpc->dev->name); - return NULL; - } - } - ether_addr_copy(mpc->mps_macs, router_mac); - tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20; - if (mps_macs > 0) - memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); - tlvs += mps_macs*ETH_ALEN; - mpc->number_of_mps_macs = num_macs; - - return tlvs; -} - -static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc) -{ - in_cache_entry *entry; - struct iphdr *iph; - char *buff; - __be32 ipaddr = 0; - - static struct { - struct llc_snap_hdr hdr; - __be32 tag; - } tagged_llc_snap_hdr = { - {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}, {0x88, 0x4c}}, - 0 - }; - - buff = skb->data + mpc->dev->hard_header_len; - iph = (struct iphdr *)buff; - ipaddr = iph->daddr; - - ddprintk("(%s) ipaddr 0x%x\n", - mpc->dev->name, ipaddr); - - entry = mpc->in_ops->get(ipaddr, mpc); - if (entry == NULL) { - entry = mpc->in_ops->add_entry(ipaddr, mpc); - if (entry != NULL) - mpc->in_ops->put(entry); - return 1; - } - /* threshold not exceeded or VCC not ready */ - if (mpc->in_ops->cache_hit(entry, mpc) != OPEN) { - ddprintk("(%s) cache_hit: returns != OPEN\n", - mpc->dev->name); - mpc->in_ops->put(entry); - return 1; - } - - ddprintk("(%s) using shortcut\n", - mpc->dev->name); - /* MPOA spec A.1.4, MPOA client must decrement IP ttl at least by one */ - if (iph->ttl <= 1) { - ddprintk("(%s) IP ttl = %u, using LANE\n", - mpc->dev->name, iph->ttl); - mpc->in_ops->put(entry); - return 1; - } - iph->ttl--; - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - - if (entry->ctrl_info.tag != 0) { - ddprintk("(%s) adding tag 0x%x\n", - mpc->dev->name, entry->ctrl_info.tag); - tagged_llc_snap_hdr.tag = entry->ctrl_info.tag; - skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ - skb_push(skb, sizeof(tagged_llc_snap_hdr)); - /* add LLC/SNAP header */ - skb_copy_to_linear_data(skb, &tagged_llc_snap_hdr, - sizeof(tagged_llc_snap_hdr)); - } else { - skb_pull(skb, ETH_HLEN); /* get rid of Eth header */ - skb_push(skb, sizeof(struct llc_snap_hdr)); - /* add LLC/SNAP header + tag */ - skb_copy_to_linear_data(skb, &llc_snap_mpoa_data, - sizeof(struct llc_snap_hdr)); - } - - atm_account_tx(entry->shortcut, skb); - entry->shortcut->send(entry->shortcut, skb); - entry->packets_fwded++; - mpc->in_ops->put(entry); - - return 0; -} - -/* - * Probably needs some error checks and locking, not sure... - */ -static netdev_tx_t mpc_send_packet(struct sk_buff *skb, - struct net_device *dev) -{ - struct mpoa_client *mpc; - struct ethhdr *eth; - int i = 0; - - mpc = find_mpc_by_lec(dev); /* this should NEVER fail */ - if (mpc == NULL) { - pr_info("(%s) no MPC found\n", dev->name); - goto non_ip; - } - - eth = (struct ethhdr *)skb->data; - if (eth->h_proto != htons(ETH_P_IP)) - goto non_ip; /* Multi-Protocol Over ATM :-) */ - - /* Weed out funny packets (e.g., AF_PACKET or raw). */ - if (skb->len < ETH_HLEN + sizeof(struct iphdr)) - goto non_ip; - skb_set_network_header(skb, ETH_HLEN); - if (skb->len < ETH_HLEN + ip_hdr(skb)->ihl * 4 || ip_hdr(skb)->ihl < 5) - goto non_ip; - - while (i < mpc->number_of_mps_macs) { - if (ether_addr_equal(eth->h_dest, mpc->mps_macs + i * ETH_ALEN)) - if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */ - return NETDEV_TX_OK; - i++; - } - -non_ip: - return __netdev_start_xmit(mpc->old_ops, skb, dev, false); -} - -static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) -{ - int bytes_left; - struct mpoa_client *mpc; - struct atmmpc_ioc ioc_data; - in_cache_entry *in_entry; - __be32 ipaddr; - - bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc)); - if (bytes_left != 0) { - pr_info("mpoa:Short read (missed %d bytes) from userland\n", - bytes_left); - return -EFAULT; - } - ipaddr = ioc_data.ipaddr; - if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF) - return -EINVAL; - - mpc = find_mpc_by_itfnum(ioc_data.dev_num); - if (mpc == NULL) - return -EINVAL; - - if (ioc_data.type == MPC_SOCKET_INGRESS) { - in_entry = mpc->in_ops->get(ipaddr, mpc); - if (in_entry == NULL || - in_entry->entry_state < INGRESS_RESOLVED) { - pr_info("(%s) did not find RESOLVED entry from ingress cache\n", - mpc->dev->name); - if (in_entry != NULL) - mpc->in_ops->put(in_entry); - return -EINVAL; - } - pr_info("(%s) attaching ingress SVC, entry = %pI4\n", - mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); - in_entry->shortcut = vcc; - mpc->in_ops->put(in_entry); - } else { - pr_info("(%s) attaching egress SVC\n", mpc->dev->name); - } - - vcc->proto_data = mpc->dev; - vcc->push = mpc_push; - - return 0; -} - -/* - * - */ -static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) -{ - struct mpoa_client *mpc; - in_cache_entry *in_entry; - eg_cache_entry *eg_entry; - - mpc = find_mpc_by_lec(dev); - if (mpc == NULL) { - pr_info("(%s) close for unknown MPC\n", dev->name); - return; - } - - dprintk("(%s)\n", dev->name); - in_entry = mpc->in_ops->get_by_vcc(vcc, mpc); - if (in_entry) { - dprintk("(%s) ingress SVC closed ip = %pI4\n", - mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); - in_entry->shortcut = NULL; - mpc->in_ops->put(in_entry); - } - eg_entry = mpc->eg_ops->get_by_vcc(vcc, mpc); - if (eg_entry) { - dprintk("(%s) egress SVC closed\n", mpc->dev->name); - eg_entry->shortcut = NULL; - mpc->eg_ops->put(eg_entry); - } - - if (in_entry == NULL && eg_entry == NULL) - dprintk("(%s) unused vcc closed\n", dev->name); -} - -static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct net_device *dev = (struct net_device *)vcc->proto_data; - struct sk_buff *new_skb; - eg_cache_entry *eg; - struct mpoa_client *mpc; - __be32 tag; - char *tmp; - - ddprintk("(%s)\n", dev->name); - if (skb == NULL) { - dprintk("(%s) null skb, closing VCC\n", dev->name); - mpc_vcc_close(vcc, dev); - return; - } - - skb->dev = dev; - if (memcmp(skb->data, &llc_snap_mpoa_ctrl, - sizeof(struct llc_snap_hdr)) == 0) { - struct sock *sk = sk_atm(vcc); - - dprintk("(%s) control packet arrived\n", dev->name); - /* Pass control packets to daemon */ - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - return; - } - - /* data coming over the shortcut */ - atm_return(vcc, skb->truesize); - - mpc = find_mpc_by_lec(dev); - if (mpc == NULL) { - pr_info("(%s) unknown MPC\n", dev->name); - return; - } - - if (memcmp(skb->data, &llc_snap_mpoa_data_tagged, - sizeof(struct llc_snap_hdr)) == 0) { /* MPOA tagged data */ - ddprintk("(%s) tagged data packet arrived\n", dev->name); - - } else if (memcmp(skb->data, &llc_snap_mpoa_data, - sizeof(struct llc_snap_hdr)) == 0) { /* MPOA data */ - pr_info("(%s) Unsupported non-tagged data packet arrived. Purging\n", - dev->name); - dev_kfree_skb_any(skb); - return; - } else { - pr_info("(%s) garbage arrived, purging\n", dev->name); - dev_kfree_skb_any(skb); - return; - } - - tmp = skb->data + sizeof(struct llc_snap_hdr); - tag = *(__be32 *)tmp; - - eg = mpc->eg_ops->get_by_tag(tag, mpc); - if (eg == NULL) { - pr_info("mpoa: (%s) Didn't find egress cache entry, tag = %u\n", - dev->name, tag); - purge_egress_shortcut(vcc, NULL); - dev_kfree_skb_any(skb); - return; - } - - /* - * See if ingress MPC is using shortcut we opened as a return channel. - * This means we have a bi-directional vcc opened by us. - */ - if (eg->shortcut == NULL) { - eg->shortcut = vcc; - pr_info("(%s) egress SVC in use\n", dev->name); - } - - skb_pull(skb, sizeof(struct llc_snap_hdr) + sizeof(tag)); - /* get rid of LLC/SNAP header */ - new_skb = skb_realloc_headroom(skb, eg->ctrl_info.DH_length); - /* LLC/SNAP is shorter than MAC header :( */ - dev_kfree_skb_any(skb); - if (new_skb == NULL) { - mpc->eg_ops->put(eg); - return; - } - skb_push(new_skb, eg->ctrl_info.DH_length); /* add MAC header */ - skb_copy_to_linear_data(new_skb, eg->ctrl_info.DLL_header, - eg->ctrl_info.DH_length); - new_skb->protocol = eth_type_trans(new_skb, dev); - skb_reset_network_header(new_skb); - - eg->latest_ip_addr = ip_hdr(new_skb)->saddr; - eg->packets_rcvd++; - mpc->eg_ops->put(eg); - - memset(ATM_SKB(new_skb), 0, sizeof(struct atm_skb_data)); - netif_rx(new_skb); -} - -static const struct atmdev_ops mpc_ops = { /* only send is required */ - .close = mpoad_close, - .send = msg_from_mpoad -}; - -static struct atm_dev mpc_dev = { - .ops = &mpc_ops, - .type = "mpc", - .number = 42, - .lock = __SPIN_LOCK_UNLOCKED(mpc_dev.lock) - /* members not explicitly initialised will be 0 */ -}; - -static int atm_mpoa_mpoad_attach(struct atm_vcc *vcc, int arg) -{ - struct mpoa_client *mpc; - struct lec_priv *priv; - int err; - - if (mpcs == NULL) { - mpc_timer_refresh(); - - /* This lets us now how our LECs are doing */ - err = register_netdevice_notifier(&mpoa_notifier); - if (err < 0) { - timer_delete(&mpc_timer); - return err; - } - } - - mpc = find_mpc_by_itfnum(arg); - if (mpc == NULL) { - dprintk("allocating new mpc for itf %d\n", arg); - mpc = alloc_mpc(); - if (mpc == NULL) - return -ENOMEM; - mpc->dev_num = arg; - mpc->dev = find_lec_by_itfnum(arg); - /* NULL if there was no lec */ - } - if (mpc->mpoad_vcc) { - pr_info("mpoad is already present for itf %d\n", arg); - return -EADDRINUSE; - } - - if (mpc->dev) { /* check if the lec is LANE2 capable */ - priv = netdev_priv(mpc->dev); - if (priv->lane_version < 2) { - dev_put(mpc->dev); - mpc->dev = NULL; - } else - priv->lane2_ops->associate_indicator = lane2_assoc_ind; - } - - mpc->mpoad_vcc = vcc; - vcc->dev = &mpc_dev; - vcc_insert_socket(sk_atm(vcc)); - set_bit(ATM_VF_META, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - if (mpc->dev) { - char empty[ATM_ESA_LEN]; - memset(empty, 0, ATM_ESA_LEN); - - start_mpc(mpc, mpc->dev); - /* set address if mpcd e.g. gets killed and restarted. - * If we do not do it now we have to wait for the next LE_ARP - */ - if (memcmp(mpc->mps_ctrl_addr, empty, ATM_ESA_LEN) != 0) - send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); - } - - __module_get(THIS_MODULE); - return arg; -} - -static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc) -{ - struct k_message mesg; - - memcpy(mpc->mps_ctrl_addr, addr, ATM_ESA_LEN); - - mesg.type = SET_MPS_CTRL_ADDR; - memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN); - msg_to_mpoad(&mesg, mpc); -} - -static void mpoad_close(struct atm_vcc *vcc) -{ - struct mpoa_client *mpc; - struct sk_buff *skb; - - mpc = find_mpc_by_vcc(vcc); - if (mpc == NULL) { - pr_info("did not find MPC\n"); - return; - } - if (!mpc->mpoad_vcc) { - pr_info("close for non-present mpoad\n"); - return; - } - - mpc->mpoad_vcc = NULL; - if (mpc->dev) { - struct lec_priv *priv = netdev_priv(mpc->dev); - priv->lane2_ops->associate_indicator = NULL; - stop_mpc(mpc); - dev_put(mpc->dev); - } - - mpc->in_ops->destroy_cache(mpc); - mpc->eg_ops->destroy_cache(mpc); - - while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue))) { - atm_return(vcc, skb->truesize); - kfree_skb(skb); - } - - pr_info("(%s) going down\n", - (mpc->dev) ? mpc->dev->name : ""); - module_put(THIS_MODULE); -} - -/* - * - */ -static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb) -{ - - struct mpoa_client *mpc = find_mpc_by_vcc(vcc); - struct k_message *mesg = (struct k_message *)skb->data; - WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc)); - - if (mpc == NULL) { - pr_info("no mpc found\n"); - return 0; - } - dprintk("(%s)", mpc->dev ? mpc->dev->name : ""); - switch (mesg->type) { - case MPOA_RES_REPLY_RCVD: - dprintk_cont("mpoa_res_reply_rcvd\n"); - MPOA_res_reply_rcvd(mesg, mpc); - break; - case MPOA_TRIGGER_RCVD: - dprintk_cont("mpoa_trigger_rcvd\n"); - MPOA_trigger_rcvd(mesg, mpc); - break; - case INGRESS_PURGE_RCVD: - dprintk_cont("nhrp_purge_rcvd\n"); - ingress_purge_rcvd(mesg, mpc); - break; - case EGRESS_PURGE_RCVD: - dprintk_cont("egress_purge_reply_rcvd\n"); - egress_purge_rcvd(mesg, mpc); - break; - case MPS_DEATH: - dprintk_cont("mps_death\n"); - mps_death(mesg, mpc); - break; - case CACHE_IMPOS_RCVD: - dprintk_cont("cache_impos_rcvd\n"); - MPOA_cache_impos_rcvd(mesg, mpc); - break; - case SET_MPC_CTRL_ADDR: - dprintk_cont("set_mpc_ctrl_addr\n"); - set_mpc_ctrl_addr_rcvd(mesg, mpc); - break; - case SET_MPS_MAC_ADDR: - dprintk_cont("set_mps_mac_addr\n"); - set_mps_mac_addr_rcvd(mesg, mpc); - break; - case CLEAN_UP_AND_EXIT: - dprintk_cont("clean_up_and_exit\n"); - clean_up(mesg, mpc, DIE); - break; - case RELOAD: - dprintk_cont("reload\n"); - clean_up(mesg, mpc, RELOAD); - break; - case SET_MPC_PARAMS: - dprintk_cont("set_mpc_params\n"); - mpc->parameters = mesg->content.params; - break; - default: - dprintk_cont("unknown message %d\n", mesg->type); - break; - } - kfree_skb(skb); - - return 0; -} - -/* Remember that this function may not do things that sleep */ -int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc) -{ - struct sk_buff *skb; - struct sock *sk; - - if (mpc == NULL || !mpc->mpoad_vcc) { - pr_info("mesg %d to a non-existent mpoad\n", mesg->type); - return -ENXIO; - } - - skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); - if (skb == NULL) - return -ENOMEM; - skb_put(skb, sizeof(struct k_message)); - skb_copy_to_linear_data(skb, mesg, sizeof(*mesg)); - atm_force_charge(mpc->mpoad_vcc, skb->truesize); - - sk = sk_atm(mpc->mpoad_vcc); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - - return 0; -} - -static int mpoa_event_listener(struct notifier_block *mpoa_notifier, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct mpoa_client *mpc; - struct lec_priv *priv; - - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - - if (strncmp(dev->name, "lec", 3)) - return NOTIFY_DONE; /* we are only interested in lec:s */ - - switch (event) { - case NETDEV_REGISTER: /* a new lec device was allocated */ - priv = netdev_priv(dev); - if (priv->lane_version < 2) - break; - priv->lane2_ops->associate_indicator = lane2_assoc_ind; - mpc = find_mpc_by_itfnum(priv->itfnum); - if (mpc == NULL) { - dprintk("allocating new mpc for %s\n", dev->name); - mpc = alloc_mpc(); - if (mpc == NULL) { - pr_info("no new mpc"); - break; - } - } - mpc->dev_num = priv->itfnum; - mpc->dev = dev; - dev_hold(dev); - dprintk("(%s) was initialized\n", dev->name); - break; - case NETDEV_UNREGISTER: - /* the lec device was deallocated */ - mpc = find_mpc_by_lec(dev); - if (mpc == NULL) - break; - dprintk("device (%s) was deallocated\n", dev->name); - stop_mpc(mpc); - dev_put(mpc->dev); - mpc->dev = NULL; - break; - case NETDEV_UP: - /* the dev was ifconfig'ed up */ - mpc = find_mpc_by_lec(dev); - if (mpc == NULL) - break; - if (mpc->mpoad_vcc != NULL) - start_mpc(mpc, dev); - break; - case NETDEV_DOWN: - /* the dev was ifconfig'ed down */ - /* this means that the flow of packets from the - * upper layer stops - */ - mpc = find_mpc_by_lec(dev); - if (mpc == NULL) - break; - if (mpc->mpoad_vcc != NULL) - stop_mpc(mpc); - break; - case NETDEV_REBOOT: - case NETDEV_CHANGE: - case NETDEV_CHANGEMTU: - case NETDEV_CHANGEADDR: - case NETDEV_GOING_DOWN: - break; - default: - break; - } - - return NOTIFY_DONE; -} - -/* - * Functions which are called after a message is received from mpcd. - * Msg is reused on purpose. - */ - - -static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc) -{ - __be32 dst_ip = msg->content.in_info.in_dst_ip; - in_cache_entry *entry; - - entry = mpc->in_ops->get(dst_ip, mpc); - if (entry == NULL) { - entry = mpc->in_ops->add_entry(dst_ip, mpc); - entry->entry_state = INGRESS_RESOLVING; - msg->type = SND_MPOA_RES_RQST; - msg->content.in_info = entry->ctrl_info; - msg_to_mpoad(msg, mpc); - entry->reply_wait = ktime_get_seconds(); - mpc->in_ops->put(entry); - return; - } - - if (entry->entry_state == INGRESS_INVALID) { - entry->entry_state = INGRESS_RESOLVING; - msg->type = SND_MPOA_RES_RQST; - msg->content.in_info = entry->ctrl_info; - msg_to_mpoad(msg, mpc); - entry->reply_wait = ktime_get_seconds(); - mpc->in_ops->put(entry); - return; - } - - pr_info("(%s) entry already in resolving state\n", - (mpc->dev) ? mpc->dev->name : ""); - mpc->in_ops->put(entry); -} - -/* - * Things get complicated because we have to check if there's an egress - * shortcut with suitable traffic parameters we could use. - */ -static void check_qos_and_open_shortcut(struct k_message *msg, - struct mpoa_client *client, - in_cache_entry *entry) -{ - __be32 dst_ip = msg->content.in_info.in_dst_ip; - struct atm_mpoa_qos *qos = atm_mpoa_search_qos(dst_ip); - eg_cache_entry *eg_entry = client->eg_ops->get_by_src_ip(dst_ip, client); - - if (eg_entry && eg_entry->shortcut) { - if (eg_entry->shortcut->qos.txtp.traffic_class & - msg->qos.txtp.traffic_class & - (qos ? qos->qos.txtp.traffic_class : ATM_UBR | ATM_CBR)) { - if (eg_entry->shortcut->qos.txtp.traffic_class == ATM_UBR) - entry->shortcut = eg_entry->shortcut; - else if (eg_entry->shortcut->qos.txtp.max_pcr > 0) - entry->shortcut = eg_entry->shortcut; - } - if (entry->shortcut) { - dprintk("(%s) using egress SVC to reach %pI4\n", - client->dev->name, &dst_ip); - client->eg_ops->put(eg_entry); - return; - } - } - if (eg_entry != NULL) - client->eg_ops->put(eg_entry); - - /* No luck in the egress cache we must open an ingress SVC */ - msg->type = OPEN_INGRESS_SVC; - if (qos && - (qos->qos.txtp.traffic_class == msg->qos.txtp.traffic_class)) { - msg->qos = qos->qos; - pr_info("(%s) trying to get a CBR shortcut\n", - client->dev->name); - } else - memset(&msg->qos, 0, sizeof(struct atm_qos)); - msg_to_mpoad(msg, client); -} - -static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) -{ - __be32 dst_ip = msg->content.in_info.in_dst_ip; - in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); - - dprintk("(%s) ip %pI4\n", - mpc->dev->name, &dst_ip); - ddprintk("(%s) entry = %p", - mpc->dev->name, entry); - if (entry == NULL) { - pr_info("(%s) ARGH, received res. reply for an entry that doesn't exist.\n", - mpc->dev->name); - return; - } - ddprintk_cont(" entry_state = %d ", entry->entry_state); - - if (entry->entry_state == INGRESS_RESOLVED) { - pr_info("(%s) RESOLVED entry!\n", mpc->dev->name); - mpc->in_ops->put(entry); - return; - } - - entry->ctrl_info = msg->content.in_info; - entry->time = ktime_get_seconds(); - /* Used in refreshing func from now on */ - entry->reply_wait = ktime_get_seconds(); - entry->refresh_time = 0; - ddprintk_cont("entry->shortcut = %p\n", entry->shortcut); - - if (entry->entry_state == INGRESS_RESOLVING && - entry->shortcut != NULL) { - entry->entry_state = INGRESS_RESOLVED; - mpc->in_ops->put(entry); - return; /* Shortcut already open... */ - } - - if (entry->shortcut != NULL) { - pr_info("(%s) entry->shortcut != NULL, impossible!\n", - mpc->dev->name); - mpc->in_ops->put(entry); - return; - } - - check_qos_and_open_shortcut(msg, mpc, entry); - entry->entry_state = INGRESS_RESOLVED; - mpc->in_ops->put(entry); - - return; - -} - -static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) -{ - __be32 dst_ip = msg->content.in_info.in_dst_ip; - __be32 mask = msg->ip_mask; - in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); - - if (entry == NULL) { - pr_info("(%s) purge for a non-existing entry, ip = %pI4\n", - mpc->dev->name, &dst_ip); - return; - } - - do { - dprintk("(%s) removing an ingress entry, ip = %pI4\n", - mpc->dev->name, &dst_ip); - write_lock_bh(&mpc->ingress_lock); - mpc->in_ops->remove_entry(entry, mpc); - write_unlock_bh(&mpc->ingress_lock); - mpc->in_ops->put(entry); - entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); - } while (entry != NULL); -} - -static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) -{ - __be32 cache_id = msg->content.eg_info.cache_id; - eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(cache_id, mpc); - - if (entry == NULL) { - dprintk("(%s) purge for a non-existing entry\n", - mpc->dev->name); - return; - } - - write_lock_irq(&mpc->egress_lock); - mpc->eg_ops->remove_entry(entry, mpc); - write_unlock_irq(&mpc->egress_lock); - - mpc->eg_ops->put(entry); -} - -static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry) -{ - struct sock *sk; - struct k_message *purge_msg; - struct sk_buff *skb; - - dprintk("entering\n"); - if (vcc == NULL) { - pr_info("vcc == NULL\n"); - return; - } - - skb = alloc_skb(sizeof(struct k_message), GFP_ATOMIC); - if (skb == NULL) { - pr_info("out of memory\n"); - return; - } - - skb_put(skb, sizeof(struct k_message)); - memset(skb->data, 0, sizeof(struct k_message)); - purge_msg = (struct k_message *)skb->data; - purge_msg->type = DATA_PLANE_PURGE; - if (entry != NULL) - purge_msg->content.eg_info = entry->ctrl_info; - - atm_force_charge(vcc, skb->truesize); - - sk = sk_atm(vcc); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - dprintk("exiting\n"); -} - -/* - * Our MPS died. Tell our daemon to send NHRP data plane purge to each - * of the egress shortcuts we have. - */ -static void mps_death(struct k_message *msg, struct mpoa_client *mpc) -{ - eg_cache_entry *entry; - - dprintk("(%s)\n", mpc->dev->name); - - if (memcmp(msg->MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN)) { - pr_info("(%s) wrong MPS\n", mpc->dev->name); - return; - } - - /* FIXME: This knows too much of the cache structure */ - read_lock_irq(&mpc->egress_lock); - entry = mpc->eg_cache; - while (entry != NULL) { - purge_egress_shortcut(entry->shortcut, entry); - entry = entry->next; - } - read_unlock_irq(&mpc->egress_lock); - - mpc->in_ops->destroy_cache(mpc); - mpc->eg_ops->destroy_cache(mpc); -} - -static void MPOA_cache_impos_rcvd(struct k_message *msg, - struct mpoa_client *mpc) -{ - uint16_t holding_time; - eg_cache_entry *entry = mpc->eg_ops->get_by_cache_id(msg->content.eg_info.cache_id, mpc); - - holding_time = msg->content.eg_info.holding_time; - dprintk("(%s) entry = %p, holding_time = %u\n", - mpc->dev->name, entry, holding_time); - if (entry == NULL && !holding_time) - return; - if (entry == NULL && holding_time) { - entry = mpc->eg_ops->add_entry(msg, mpc); - mpc->eg_ops->put(entry); - return; - } - if (holding_time) { - mpc->eg_ops->update(entry, holding_time); - return; - } - - write_lock_irq(&mpc->egress_lock); - mpc->eg_ops->remove_entry(entry, mpc); - write_unlock_irq(&mpc->egress_lock); - - mpc->eg_ops->put(entry); -} - -static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, - struct mpoa_client *mpc) -{ - struct lec_priv *priv; - int i, retval ; - - uint8_t tlv[4 + 1 + 1 + 1 + ATM_ESA_LEN]; - - tlv[0] = 00; tlv[1] = 0xa0; tlv[2] = 0x3e; tlv[3] = 0x2a; /* type */ - tlv[4] = 1 + 1 + ATM_ESA_LEN; /* length */ - tlv[5] = 0x02; /* MPOA client */ - tlv[6] = 0x00; /* number of MPS MAC addresses */ - - memcpy(&tlv[7], mesg->MPS_ctrl, ATM_ESA_LEN); /* MPC ctrl ATM addr */ - memcpy(mpc->our_ctrl_addr, mesg->MPS_ctrl, ATM_ESA_LEN); - - dprintk("(%s) setting MPC ctrl ATM address to", - mpc->dev ? mpc->dev->name : ""); - for (i = 7; i < sizeof(tlv); i++) - dprintk_cont(" %02x", tlv[i]); - dprintk_cont("\n"); - - if (mpc->dev) { - priv = netdev_priv(mpc->dev); - retval = priv->lane2_ops->associate_req(mpc->dev, - mpc->dev->dev_addr, - tlv, sizeof(tlv)); - if (retval == 0) - pr_info("(%s) MPOA device type TLV association failed\n", - mpc->dev->name); - retval = priv->lane2_ops->resolve(mpc->dev, NULL, 1, NULL, NULL); - if (retval < 0) - pr_info("(%s) targetless LE_ARP request failed\n", - mpc->dev->name); - } -} - -static void set_mps_mac_addr_rcvd(struct k_message *msg, - struct mpoa_client *client) -{ - - if (client->number_of_mps_macs) - kfree(client->mps_macs); - client->number_of_mps_macs = 0; - client->mps_macs = kmemdup(msg->MPS_ctrl, ETH_ALEN, GFP_KERNEL); - if (client->mps_macs == NULL) { - pr_info("out of memory\n"); - return; - } - client->number_of_mps_macs = 1; -} - -/* - * purge egress cache and tell daemon to 'action' (DIE, RELOAD) - */ -static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action) -{ - - eg_cache_entry *entry; - msg->type = SND_EGRESS_PURGE; - - - /* FIXME: This knows too much of the cache structure */ - read_lock_irq(&mpc->egress_lock); - entry = mpc->eg_cache; - while (entry != NULL) { - msg->content.eg_info = entry->ctrl_info; - dprintk("cache_id %u\n", entry->ctrl_info.cache_id); - msg_to_mpoad(msg, mpc); - entry = entry->next; - } - read_unlock_irq(&mpc->egress_lock); - - msg->type = action; - msg_to_mpoad(msg, mpc); -} - -static unsigned long checking_time; - -static void mpc_timer_refresh(void) -{ - mpc_timer.expires = jiffies + (MPC_P2 * HZ); - checking_time = mpc_timer.expires; - add_timer(&mpc_timer); -} - -static void mpc_cache_check(struct timer_list *unused) -{ - struct mpoa_client *mpc = mpcs; - static unsigned long previous_resolving_check_time; - static unsigned long previous_refresh_time; - - while (mpc != NULL) { - mpc->in_ops->clear_count(mpc); - mpc->eg_ops->clear_expired(mpc); - if (checking_time - previous_resolving_check_time > - mpc->parameters.mpc_p4 * HZ) { - mpc->in_ops->check_resolving(mpc); - previous_resolving_check_time = checking_time; - } - if (checking_time - previous_refresh_time > - mpc->parameters.mpc_p5 * HZ) { - mpc->in_ops->refresh(mpc); - previous_refresh_time = checking_time; - } - mpc = mpc->next; - } - mpc_timer_refresh(); -} - -static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) -{ - int err = 0; - struct atm_vcc *vcc = ATM_SD(sock); - - if (cmd != ATMMPC_CTRL && cmd != ATMMPC_DATA) - return -ENOIOCTLCMD; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch (cmd) { - case ATMMPC_CTRL: - err = atm_mpoa_mpoad_attach(vcc, (int)arg); - if (err >= 0) - sock->state = SS_CONNECTED; - break; - case ATMMPC_DATA: - err = atm_mpoa_vcc_attach(vcc, (void __user *)arg); - break; - default: - break; - } - return err; -} - -static struct atm_ioctl atm_ioctl_ops = { - .owner = THIS_MODULE, - .ioctl = atm_mpoa_ioctl, -}; - -static __init int atm_mpoa_init(void) -{ - register_atm_ioctl(&atm_ioctl_ops); - - if (mpc_proc_init() != 0) - pr_info("failed to initialize /proc/mpoa\n"); - - pr_info("mpc.c: initialized\n"); - - return 0; -} - -static void __exit atm_mpoa_cleanup(void) -{ - struct mpoa_client *mpc, *tmp; - struct atm_mpoa_qos *qos, *nextqos; - struct lec_priv *priv; - - mpc_proc_clean(); - - timer_delete_sync(&mpc_timer); - unregister_netdevice_notifier(&mpoa_notifier); - deregister_atm_ioctl(&atm_ioctl_ops); - - mpc = mpcs; - mpcs = NULL; - while (mpc != NULL) { - tmp = mpc->next; - if (mpc->dev != NULL) { - stop_mpc(mpc); - priv = netdev_priv(mpc->dev); - if (priv->lane2_ops != NULL) - priv->lane2_ops->associate_indicator = NULL; - } - ddprintk("about to clear caches\n"); - mpc->in_ops->destroy_cache(mpc); - mpc->eg_ops->destroy_cache(mpc); - ddprintk("caches cleared\n"); - kfree(mpc->mps_macs); - memset(mpc, 0, sizeof(struct mpoa_client)); - ddprintk("about to kfree %p\n", mpc); - kfree(mpc); - ddprintk("next mpc is at %p\n", tmp); - mpc = tmp; - } - - qos = qos_head; - qos_head = NULL; - while (qos != NULL) { - nextqos = qos->next; - dprintk("freeing qos entry %p\n", qos); - kfree(qos); - qos = nextqos; - } -} - -module_init(atm_mpoa_init); -module_exit(atm_mpoa_cleanup); - -MODULE_DESCRIPTION("Multi-Protocol Over ATM (MPOA) driver"); -MODULE_LICENSE("GPL"); diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c deleted file mode 100644 index c8d4e6f2e831..000000000000 --- a/net/atm/mpoa_caches.c +++ /dev/null @@ -1,565 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include - -#include "mpoa_caches.h" -#include "mpc.h" - -/* - * mpoa_caches.c: Implementation of ingress and egress cache - * handling functions - */ - -#if 0 -#define dprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ -#else -#define dprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ - } while (0) -#endif - -#if 0 -#define ddprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ -#else -#define ddprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ - } while (0) -#endif - -static in_cache_entry *in_cache_get(__be32 dst_ip, - struct mpoa_client *client) -{ - in_cache_entry *entry; - - read_lock_bh(&client->ingress_lock); - entry = client->in_cache; - while (entry != NULL) { - if (entry->ctrl_info.in_dst_ip == dst_ip) { - refcount_inc(&entry->use); - read_unlock_bh(&client->ingress_lock); - return entry; - } - entry = entry->next; - } - read_unlock_bh(&client->ingress_lock); - - return NULL; -} - -static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip, - struct mpoa_client *client, - __be32 mask) -{ - in_cache_entry *entry; - - read_lock_bh(&client->ingress_lock); - entry = client->in_cache; - while (entry != NULL) { - if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) { - refcount_inc(&entry->use); - read_unlock_bh(&client->ingress_lock); - return entry; - } - entry = entry->next; - } - read_unlock_bh(&client->ingress_lock); - - return NULL; - -} - -static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc, - struct mpoa_client *client) -{ - in_cache_entry *entry; - - read_lock_bh(&client->ingress_lock); - entry = client->in_cache; - while (entry != NULL) { - if (entry->shortcut == vcc) { - refcount_inc(&entry->use); - read_unlock_bh(&client->ingress_lock); - return entry; - } - entry = entry->next; - } - read_unlock_bh(&client->ingress_lock); - - return NULL; -} - -static in_cache_entry *in_cache_add_entry(__be32 dst_ip, - struct mpoa_client *client) -{ - in_cache_entry *entry = kzalloc_obj(in_cache_entry); - - if (entry == NULL) { - pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n"); - return NULL; - } - - dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip); - - refcount_set(&entry->use, 1); - dprintk("new_in_cache_entry: about to lock\n"); - write_lock_bh(&client->ingress_lock); - entry->next = client->in_cache; - entry->prev = NULL; - if (client->in_cache != NULL) - client->in_cache->prev = entry; - client->in_cache = entry; - - memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); - entry->ctrl_info.in_dst_ip = dst_ip; - entry->time = ktime_get_seconds(); - entry->retry_time = client->parameters.mpc_p4; - entry->count = 1; - entry->entry_state = INGRESS_INVALID; - entry->ctrl_info.holding_time = HOLDING_TIME_DEFAULT; - refcount_inc(&entry->use); - - write_unlock_bh(&client->ingress_lock); - dprintk("new_in_cache_entry: unlocked\n"); - - return entry; -} - -static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) -{ - struct atm_mpoa_qos *qos; - struct k_message msg; - - entry->count++; - if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL) - return OPEN; - - if (entry->entry_state == INGRESS_REFRESHING) { - if (entry->count > mpc->parameters.mpc_p1) { - msg.type = SND_MPOA_RES_RQST; - msg.content.in_info = entry->ctrl_info; - memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); - qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) - msg.qos = qos->qos; - msg_to_mpoad(&msg, mpc); - entry->reply_wait = ktime_get_seconds(); - entry->entry_state = INGRESS_RESOLVING; - } - if (entry->shortcut != NULL) - return OPEN; - return CLOSED; - } - - if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL) - return OPEN; - - if (entry->count > mpc->parameters.mpc_p1 && - entry->entry_state == INGRESS_INVALID) { - dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n", - mpc->dev->name, &entry->ctrl_info.in_dst_ip); - entry->entry_state = INGRESS_RESOLVING; - msg.type = SND_MPOA_RES_RQST; - memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN); - msg.content.in_info = entry->ctrl_info; - qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) - msg.qos = qos->qos; - msg_to_mpoad(&msg, mpc); - entry->reply_wait = ktime_get_seconds(); - } - - return CLOSED; -} - -static void in_cache_put(in_cache_entry *entry) -{ - if (refcount_dec_and_test(&entry->use)) { - kfree_sensitive(entry); - } -} - -/* - * This should be called with write lock on - */ -static void in_cache_remove_entry(in_cache_entry *entry, - struct mpoa_client *client) -{ - struct atm_vcc *vcc; - struct k_message msg; - - vcc = entry->shortcut; - dprintk("removing an ingress entry, ip = %pI4\n", - &entry->ctrl_info.in_dst_ip); - - if (entry->prev != NULL) - entry->prev->next = entry->next; - else - client->in_cache = entry->next; - if (entry->next != NULL) - entry->next->prev = entry->prev; - client->in_ops->put(entry); - if (client->in_cache == NULL && client->eg_cache == NULL) { - msg.type = STOP_KEEP_ALIVE_SM; - msg_to_mpoad(&msg, client); - } - - /* Check if the egress side still uses this VCC */ - if (vcc != NULL) { - eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, - client); - if (eg_entry != NULL) { - client->eg_ops->put(eg_entry); - return; - } - vcc_release_async(vcc, -EPIPE); - } -} - -/* Call this every MPC-p2 seconds... Not exactly correct solution, - but an easy one... */ -static void clear_count_and_expired(struct mpoa_client *client) -{ - in_cache_entry *entry, *next_entry; - time64_t now; - - now = ktime_get_seconds(); - - write_lock_bh(&client->ingress_lock); - entry = client->in_cache; - while (entry != NULL) { - entry->count = 0; - next_entry = entry->next; - if ((now - entry->time) > entry->ctrl_info.holding_time) { - dprintk("holding time expired, ip = %pI4\n", - &entry->ctrl_info.in_dst_ip); - client->in_ops->remove_entry(entry, client); - } - entry = next_entry; - } - write_unlock_bh(&client->ingress_lock); -} - -/* Call this every MPC-p4 seconds. */ -static void check_resolving_entries(struct mpoa_client *client) -{ - - struct atm_mpoa_qos *qos; - in_cache_entry *entry; - time64_t now; - struct k_message msg; - - now = ktime_get_seconds(); - - read_lock_bh(&client->ingress_lock); - entry = client->in_cache; - while (entry != NULL) { - if (entry->entry_state == INGRESS_RESOLVING) { - - if ((now - entry->hold_down) - < client->parameters.mpc_p6) { - entry = entry->next; /* Entry in hold down */ - continue; - } - if ((now - entry->reply_wait) > entry->retry_time) { - entry->retry_time = MPC_C1 * (entry->retry_time); - /* - * Retry time maximum exceeded, - * put entry in hold down. - */ - if (entry->retry_time > client->parameters.mpc_p5) { - entry->hold_down = ktime_get_seconds(); - entry->retry_time = client->parameters.mpc_p4; - entry = entry->next; - continue; - } - /* Ask daemon to send a resolution request. */ - memset(&entry->hold_down, 0, sizeof(time64_t)); - msg.type = SND_MPOA_RES_RTRY; - memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN); - msg.content.in_info = entry->ctrl_info; - qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip); - if (qos != NULL) - msg.qos = qos->qos; - msg_to_mpoad(&msg, client); - entry->reply_wait = ktime_get_seconds(); - } - } - entry = entry->next; - } - read_unlock_bh(&client->ingress_lock); -} - -/* Call this every MPC-p5 seconds. */ -static void refresh_entries(struct mpoa_client *client) -{ - time64_t now; - struct in_cache_entry *entry = client->in_cache; - - ddprintk("refresh_entries\n"); - now = ktime_get_seconds(); - - read_lock_bh(&client->ingress_lock); - while (entry != NULL) { - if (entry->entry_state == INGRESS_RESOLVED) { - if (!(entry->refresh_time)) - entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3; - if ((now - entry->reply_wait) > - entry->refresh_time) { - dprintk("refreshing an entry.\n"); - entry->entry_state = INGRESS_REFRESHING; - - } - } - entry = entry->next; - } - read_unlock_bh(&client->ingress_lock); -} - -static void in_destroy_cache(struct mpoa_client *mpc) -{ - write_lock_irq(&mpc->ingress_lock); - while (mpc->in_cache != NULL) - mpc->in_ops->remove_entry(mpc->in_cache, mpc); - write_unlock_irq(&mpc->ingress_lock); -} - -static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, - struct mpoa_client *mpc) -{ - eg_cache_entry *entry; - - read_lock_irq(&mpc->egress_lock); - entry = mpc->eg_cache; - while (entry != NULL) { - if (entry->ctrl_info.cache_id == cache_id) { - refcount_inc(&entry->use); - read_unlock_irq(&mpc->egress_lock); - return entry; - } - entry = entry->next; - } - read_unlock_irq(&mpc->egress_lock); - - return NULL; -} - -/* This can be called from any context since it saves CPU flags */ -static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc) -{ - unsigned long flags; - eg_cache_entry *entry; - - read_lock_irqsave(&mpc->egress_lock, flags); - entry = mpc->eg_cache; - while (entry != NULL) { - if (entry->ctrl_info.tag == tag) { - refcount_inc(&entry->use); - read_unlock_irqrestore(&mpc->egress_lock, flags); - return entry; - } - entry = entry->next; - } - read_unlock_irqrestore(&mpc->egress_lock, flags); - - return NULL; -} - -/* This can be called from any context since it saves CPU flags */ -static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, - struct mpoa_client *mpc) -{ - unsigned long flags; - eg_cache_entry *entry; - - read_lock_irqsave(&mpc->egress_lock, flags); - entry = mpc->eg_cache; - while (entry != NULL) { - if (entry->shortcut == vcc) { - refcount_inc(&entry->use); - read_unlock_irqrestore(&mpc->egress_lock, flags); - return entry; - } - entry = entry->next; - } - read_unlock_irqrestore(&mpc->egress_lock, flags); - - return NULL; -} - -static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, - struct mpoa_client *mpc) -{ - eg_cache_entry *entry; - - read_lock_irq(&mpc->egress_lock); - entry = mpc->eg_cache; - while (entry != NULL) { - if (entry->latest_ip_addr == ipaddr) { - refcount_inc(&entry->use); - read_unlock_irq(&mpc->egress_lock); - return entry; - } - entry = entry->next; - } - read_unlock_irq(&mpc->egress_lock); - - return NULL; -} - -static void eg_cache_put(eg_cache_entry *entry) -{ - if (refcount_dec_and_test(&entry->use)) { - kfree_sensitive(entry); - } -} - -/* - * This should be called with write lock on - */ -static void eg_cache_remove_entry(eg_cache_entry *entry, - struct mpoa_client *client) -{ - struct atm_vcc *vcc; - struct k_message msg; - - vcc = entry->shortcut; - dprintk("removing an egress entry.\n"); - if (entry->prev != NULL) - entry->prev->next = entry->next; - else - client->eg_cache = entry->next; - if (entry->next != NULL) - entry->next->prev = entry->prev; - client->eg_ops->put(entry); - if (client->in_cache == NULL && client->eg_cache == NULL) { - msg.type = STOP_KEEP_ALIVE_SM; - msg_to_mpoad(&msg, client); - } - - /* Check if the ingress side still uses this VCC */ - if (vcc != NULL) { - in_cache_entry *in_entry = client->in_ops->get_by_vcc(vcc, client); - if (in_entry != NULL) { - client->in_ops->put(in_entry); - return; - } - vcc_release_async(vcc, -EPIPE); - } -} - -static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, - struct mpoa_client *client) -{ - eg_cache_entry *entry = kzalloc_obj(eg_cache_entry); - - if (entry == NULL) { - pr_info("out of memory\n"); - return NULL; - } - - dprintk("adding an egress entry, ip = %pI4, this should be our IP\n", - &msg->content.eg_info.eg_dst_ip); - - refcount_set(&entry->use, 1); - dprintk("new_eg_cache_entry: about to lock\n"); - write_lock_irq(&client->egress_lock); - entry->next = client->eg_cache; - entry->prev = NULL; - if (client->eg_cache != NULL) - client->eg_cache->prev = entry; - client->eg_cache = entry; - - memcpy(entry->MPS_ctrl_ATM_addr, client->mps_ctrl_addr, ATM_ESA_LEN); - entry->ctrl_info = msg->content.eg_info; - entry->time = ktime_get_seconds(); - entry->entry_state = EGRESS_RESOLVED; - dprintk("new_eg_cache_entry cache_id %u\n", - ntohl(entry->ctrl_info.cache_id)); - dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip); - refcount_inc(&entry->use); - - write_unlock_irq(&client->egress_lock); - dprintk("new_eg_cache_entry: unlocked\n"); - - return entry; -} - -static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time) -{ - entry->time = ktime_get_seconds(); - entry->entry_state = EGRESS_RESOLVED; - entry->ctrl_info.holding_time = holding_time; -} - -static void clear_expired(struct mpoa_client *client) -{ - eg_cache_entry *entry, *next_entry; - time64_t now; - struct k_message msg; - - now = ktime_get_seconds(); - - write_lock_irq(&client->egress_lock); - entry = client->eg_cache; - while (entry != NULL) { - next_entry = entry->next; - if ((now - entry->time) > entry->ctrl_info.holding_time) { - msg.type = SND_EGRESS_PURGE; - msg.content.eg_info = entry->ctrl_info; - dprintk("egress_cache: holding time expired, cache_id = %u.\n", - ntohl(entry->ctrl_info.cache_id)); - msg_to_mpoad(&msg, client); - client->eg_ops->remove_entry(entry, client); - } - entry = next_entry; - } - write_unlock_irq(&client->egress_lock); -} - -static void eg_destroy_cache(struct mpoa_client *mpc) -{ - write_lock_irq(&mpc->egress_lock); - while (mpc->eg_cache != NULL) - mpc->eg_ops->remove_entry(mpc->eg_cache, mpc); - write_unlock_irq(&mpc->egress_lock); -} - - -static const struct in_cache_ops ingress_ops = { - .add_entry = in_cache_add_entry, - .get = in_cache_get, - .get_with_mask = in_cache_get_with_mask, - .get_by_vcc = in_cache_get_by_vcc, - .put = in_cache_put, - .remove_entry = in_cache_remove_entry, - .cache_hit = cache_hit, - .clear_count = clear_count_and_expired, - .check_resolving = check_resolving_entries, - .refresh = refresh_entries, - .destroy_cache = in_destroy_cache -}; - -static const struct eg_cache_ops egress_ops = { - .add_entry = eg_cache_add_entry, - .get_by_cache_id = eg_cache_get_by_cache_id, - .get_by_tag = eg_cache_get_by_tag, - .get_by_vcc = eg_cache_get_by_vcc, - .get_by_src_ip = eg_cache_get_by_src_ip, - .put = eg_cache_put, - .remove_entry = eg_cache_remove_entry, - .update = update_eg_cache_entry, - .clear_expired = clear_expired, - .destroy_cache = eg_destroy_cache -}; - -void atm_mpoa_init_cache(struct mpoa_client *mpc) -{ - mpc->in_ops = &ingress_ops; - mpc->eg_ops = &egress_ops; -} diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c deleted file mode 100644 index aaf64b953915..000000000000 --- a/net/atm/mpoa_proc.c +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#ifdef CONFIG_PROC_FS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mpc.h" -#include "mpoa_caches.h" - -/* - * mpoa_proc.c: Implementation MPOA client's proc - * file system statistics - */ - -#if 1 -#define dprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ -#else -#define dprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ - } while (0) -#endif - -#if 0 -#define ddprintk(format, args...) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */ -#else -#define ddprintk(format, args...) \ - do { if (0) \ - printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\ - } while (0) -#endif - -#define STAT_FILE_NAME "mpc" /* Our statistic file's name */ - -extern struct mpoa_client *mpcs; -extern struct proc_dir_entry *atm_proc_root; /* from proc.c. */ - -static int proc_mpc_open(struct inode *inode, struct file *file); -static ssize_t proc_mpc_write(struct file *file, const char __user *buff, - size_t nbytes, loff_t *ppos); - -static int parse_qos(const char *buff); - -static const struct proc_ops mpc_proc_ops = { - .proc_open = proc_mpc_open, - .proc_read = seq_read, - .proc_lseek = seq_lseek, - .proc_write = proc_mpc_write, - .proc_release = seq_release, -}; - -/* - * Returns the state of an ingress cache entry as a string - */ -static const char *ingress_state_string(int state) -{ - switch (state) { - case INGRESS_RESOLVING: - return "resolving "; - case INGRESS_RESOLVED: - return "resolved "; - case INGRESS_INVALID: - return "invalid "; - case INGRESS_REFRESHING: - return "refreshing "; - } - - return ""; -} - -/* - * Returns the state of an egress cache entry as a string - */ -static const char *egress_state_string(int state) -{ - switch (state) { - case EGRESS_RESOLVED: - return "resolved "; - case EGRESS_PURGE: - return "purge "; - case EGRESS_INVALID: - return "invalid "; - } - - return ""; -} - -/* - * FIXME: mpcs (and per-mpc lists) have no locking whatsoever. - */ - -static void *mpc_start(struct seq_file *m, loff_t *pos) -{ - loff_t l = *pos; - struct mpoa_client *mpc; - - if (!l--) - return SEQ_START_TOKEN; - for (mpc = mpcs; mpc; mpc = mpc->next) - if (!l--) - return mpc; - return NULL; -} - -static void *mpc_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct mpoa_client *p = v; - (*pos)++; - return v == SEQ_START_TOKEN ? mpcs : p->next; -} - -static void mpc_stop(struct seq_file *m, void *v) -{ -} - -/* - * READING function - called when the /proc/atm/mpoa file is read from. - */ -static int mpc_show(struct seq_file *m, void *v) -{ - struct mpoa_client *mpc = v; - int i; - in_cache_entry *in_entry; - eg_cache_entry *eg_entry; - time64_t now; - unsigned char ip_string[16]; - - if (v == SEQ_START_TOKEN) { - atm_mpoa_disp_qos(m); - return 0; - } - - seq_printf(m, "\nInterface %d:\n\n", mpc->dev_num); - seq_printf(m, "Ingress Entries:\nIP address State Holding time Packets fwded VPI VCI\n"); - now = ktime_get_seconds(); - - for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) { - unsigned long seconds_delta = now - in_entry->time; - - sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip); - seq_printf(m, "%-16s%s%-14lu%-12u", - ip_string, - ingress_state_string(in_entry->entry_state), - in_entry->ctrl_info.holding_time - - seconds_delta, - in_entry->packets_fwded); - if (in_entry->shortcut) - seq_printf(m, " %-3d %-3d", - in_entry->shortcut->vpi, - in_entry->shortcut->vci); - seq_printf(m, "\n"); - } - - seq_printf(m, "\n"); - seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n"); - for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) { - unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr; - unsigned long seconds_delta = now - eg_entry->time; - - for (i = 0; i < ATM_ESA_LEN; i++) - seq_printf(m, "%02x", p[i]); - seq_printf(m, "\n%-16lu%s%-14lu%-15u", - (unsigned long)ntohl(eg_entry->ctrl_info.cache_id), - egress_state_string(eg_entry->entry_state), - (eg_entry->ctrl_info.holding_time - seconds_delta), - eg_entry->packets_rcvd); - - /* latest IP address */ - sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr); - seq_printf(m, "%-16s", ip_string); - - if (eg_entry->shortcut) - seq_printf(m, " %-3d %-3d", - eg_entry->shortcut->vpi, - eg_entry->shortcut->vci); - seq_printf(m, "\n"); - } - seq_printf(m, "\n"); - return 0; -} - -static const struct seq_operations mpc_op = { - .start = mpc_start, - .next = mpc_next, - .stop = mpc_stop, - .show = mpc_show -}; - -static int proc_mpc_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &mpc_op); -} - -static ssize_t proc_mpc_write(struct file *file, const char __user *buff, - size_t nbytes, loff_t *ppos) -{ - char *page, *p; - unsigned int len; - - if (nbytes == 0) - return 0; - - if (nbytes >= PAGE_SIZE) - nbytes = PAGE_SIZE-1; - - page = (char *)__get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - for (p = page, len = 0; len < nbytes; p++) { - if (get_user(*p, buff++)) { - free_page((unsigned long)page); - return -EFAULT; - } - len += 1; - if (*p == '\0' || *p == '\n') - break; - } - - *p = '\0'; - - if (!parse_qos(page)) - printk("mpoa: proc_mpc_write: could not parse '%s'\n", page); - - free_page((unsigned long)page); - - return len; -} - -static int parse_qos(const char *buff) -{ - /* possible lines look like this - * add 130.230.54.142 tx=max_pcr,max_sdu rx=max_pcr,max_sdu - */ - unsigned char ip[4]; - int tx_pcr, tx_sdu, rx_pcr, rx_sdu; - __be32 ipaddr; - struct atm_qos qos; - - memset(&qos, 0, sizeof(struct atm_qos)); - - if (sscanf(buff, "del %hhu.%hhu.%hhu.%hhu", - ip, ip+1, ip+2, ip+3) == 4) { - ipaddr = *(__be32 *)ip; - return atm_mpoa_delete_qos(atm_mpoa_search_qos(ipaddr)); - } - - if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=tx", - ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu) == 6) { - rx_pcr = tx_pcr; - rx_sdu = tx_sdu; - } else if (sscanf(buff, "add %hhu.%hhu.%hhu.%hhu tx=%d,%d rx=%d,%d", - ip, ip+1, ip+2, ip+3, &tx_pcr, &tx_sdu, &rx_pcr, &rx_sdu) != 8) - return 0; - - ipaddr = *(__be32 *)ip; - qos.txtp.traffic_class = ATM_CBR; - qos.txtp.max_pcr = tx_pcr; - qos.txtp.max_sdu = tx_sdu; - qos.rxtp.traffic_class = ATM_CBR; - qos.rxtp.max_pcr = rx_pcr; - qos.rxtp.max_sdu = rx_sdu; - qos.aal = ATM_AAL5; - dprintk("parse_qos(): setting qos parameters to tx=%d,%d rx=%d,%d\n", - qos.txtp.max_pcr, qos.txtp.max_sdu, - qos.rxtp.max_pcr, qos.rxtp.max_sdu); - - atm_mpoa_add_qos(ipaddr, &qos); - return 1; -} - -/* - * INITIALIZATION function - called when module is initialized/loaded. - */ -int mpc_proc_init(void) -{ - struct proc_dir_entry *p; - - p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_proc_ops); - if (!p) { - pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME); - return -ENOMEM; - } - return 0; -} - -/* - * DELETING function - called when module is removed. - */ -void mpc_proc_clean(void) -{ - remove_proc_entry(STAT_FILE_NAME, atm_proc_root); -} - -#endif /* CONFIG_PROC_FS */ diff --git a/net/bridge/br.c b/net/bridge/br.c index c37e52e2f29a..a5e5b2db110e 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -464,10 +464,6 @@ static int __init br_init(void) brioctl_set(br_ioctl_stub); -#if IS_ENABLED(CONFIG_ATM_LANE) - br_fdb_test_addr_hook = br_fdb_test_addr; -#endif - #if IS_MODULE(CONFIG_BRIDGE_NETFILTER) pr_info("bridge: filtering via arp/ip/ip6tables is no longer available " "by default. Update your scripts to load br_netfilter if you " @@ -506,9 +502,6 @@ static void __exit br_deinit(void) rcu_barrier(); /* Wait for completion of call_rcu()'s */ br_nf_core_fini(); -#if IS_ENABLED(CONFIG_ATM_LANE) - br_fdb_test_addr_hook = NULL; -#endif br_fdb_fini(); } diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index e2c17f620f00..9bcf6243914b 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -892,35 +892,6 @@ void br_fdb_delete_by_port(struct net_bridge *br, spin_unlock_bh(&br->hash_lock); } -#if IS_ENABLED(CONFIG_ATM_LANE) -/* Interface used by ATM LANE hook to test - * if an addr is on some other bridge port */ -int br_fdb_test_addr(struct net_device *dev, unsigned char *addr) -{ - struct net_bridge_fdb_entry *fdb; - struct net_bridge_port *port; - int ret; - - rcu_read_lock(); - port = br_port_get_rcu(dev); - if (!port) - ret = 0; - else { - const struct net_bridge_port *dst = NULL; - - fdb = br_fdb_find_rcu(port->br, addr, 0); - if (fdb) - dst = READ_ONCE(fdb->dst); - - ret = dst && dst->dev != dev && - dst->state == BR_STATE_FORWARDING; - } - rcu_read_unlock(); - - return ret; -} -#endif /* CONFIG_ATM_LANE */ - /* * Fill buffer with forwarding table records in * the API format. diff --git a/net/core/dev.c b/net/core/dev.c index e59f6025067c..1be81928d6c7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5862,13 +5862,6 @@ static __latent_entropy void net_tx_action(void) xfrm_dev_backlog(sd); } -#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_ATM_LANE) -/* This hook is defined here for ATM LANE */ -int (*br_fdb_test_addr_hook)(struct net_device *dev, - unsigned char *addr) __read_mostly; -EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); -#endif - /** * netdev_is_rx_handler_busy - check if receive handler is registered * @dev: device to check diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index 81199dddcde7..950b48c3b111 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig @@ -52,10 +52,6 @@ CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_ATM=y -CONFIG_ATM_CLIP=y -CONFIG_ATM_LANE=m -CONFIG_ATM_MPOA=m -CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_ATALK=m @@ -108,7 +104,6 @@ CONFIG_ATA=y CONFIG_PATA_IXP4XX_CF=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_ATM_TCP=m CONFIG_IXP4XX_ETH=y CONFIG_WAN=y CONFIG_HDLC=y diff --git a/arch/mips/configs/gpr_defconfig b/arch/mips/configs/gpr_defconfig index 261730af75c7..ad80ad2eae6b 100644 --- a/arch/mips/configs/gpr_defconfig +++ b/arch/mips/configs/gpr_defconfig @@ -87,10 +87,6 @@ CONFIG_BRIDGE_EBT_LOG=m CONFIG_IP_SCTP=m CONFIG_TIPC=m CONFIG_ATM=y -CONFIG_ATM_CLIP=y -CONFIG_ATM_LANE=m -CONFIG_ATM_MPOA=m -CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_LLC2=m @@ -156,15 +152,6 @@ CONFIG_SCSI_SAS_LIBSAS=m CONFIG_NETDEVICES=y CONFIG_NET_FC=y CONFIG_NETCONSOLE=m -CONFIG_ATM_TCP=m -CONFIG_ATM_LANAI=m -CONFIG_ATM_ENI=m -CONFIG_ATM_NICSTAR=m -CONFIG_ATM_IDT77252=m -CONFIG_ATM_IA=m -CONFIG_ATM_FORE200E=m -CONFIG_ATM_HE=m -CONFIG_ATM_HE_USE_SUNI=y CONFIG_MIPS_AU1X00_ENET=y CONFIG_CICADA_PHY=m CONFIG_DAVICOM_PHY=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 315650c6fe0b..1295164af08e 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -133,10 +133,6 @@ CONFIG_BRIDGE_EBT_LOG=m CONFIG_IP_SCTP=m CONFIG_TIPC=m CONFIG_ATM=y -CONFIG_ATM_CLIP=y -CONFIG_ATM_LANE=m -CONFIG_ATM_MPOA=m -CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_LLC2=m @@ -232,15 +228,6 @@ CONFIG_ARCNET_RIM_I=m CONFIG_ARCNET_COM20020=m CONFIG_ARCNET_COM20020_PCI=m CONFIG_ARCNET_COM20020_CS=m -CONFIG_ATM_TCP=m -CONFIG_ATM_LANAI=m -CONFIG_ATM_ENI=m -CONFIG_ATM_NICSTAR=m -CONFIG_ATM_IDT77252=m -CONFIG_ATM_IA=m -CONFIG_ATM_FORE200E=m -CONFIG_ATM_HE=m -CONFIG_ATM_HE_USE_SUNI=y CONFIG_PCMCIA_3C574=m CONFIG_PCMCIA_3C589=m CONFIG_VORTEX=m diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index 6f40a275b7a9..02cc17e353a3 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -227,9 +227,6 @@ CONFIG_BRIDGE_EBT_LOG=m CONFIG_BRIDGE_EBT_NFLOG=m CONFIG_TIPC=m CONFIG_ATM=m -CONFIG_ATM_CLIP=m -CONFIG_ATM_LANE=m -CONFIG_ATM_BR2684=m CONFIG_BRIDGE=m CONFIG_VLAN_8021Q=m CONFIG_ATALK=m @@ -398,12 +395,6 @@ CONFIG_NETCONSOLE=m CONFIG_TUN=m CONFIG_VETH=m CONFIG_VIRTIO_NET=m -CONFIG_ATM_TCP=m -CONFIG_ATM_LANAI=m -CONFIG_ATM_ENI=m -CONFIG_ATM_NICSTAR=m -CONFIG_ATM_IDT77252=m -CONFIG_ATM_HE=m CONFIG_EL3=m CONFIG_PCMCIA_3C574=m CONFIG_PCMCIA_3C589=m diff --git a/drivers/atm/.gitignore b/drivers/atm/.gitignore deleted file mode 100644 index ddd374e91965..000000000000 --- a/drivers/atm/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -fore200e_mkfirm -fore200e_pca_fw.c -pca200e.bin -pca200e_ecd.bin2 diff --git a/drivers/atm/nicstarmac.copyright b/drivers/atm/nicstarmac.copyright deleted file mode 100644 index 180531a83c62..000000000000 --- a/drivers/atm/nicstarmac.copyright +++ /dev/null @@ -1,61 +0,0 @@ -/* nicstar.c v0.22 Jawaid Bazyar (bazyar@hypermall.com) - * nicstar.c, M. Welsh (matt.welsh@cl.cam.ac.uk) - * - * Hacked October, 1997 by Jawaid Bazyar, Interlink Advertising Services Inc. - * http://www.hypermall.com/ - * 10/1/97 - commented out CFG_PHYIE bit - we don't care when the PHY - * interrupts us (except possibly for removal/insertion of the cable?) - * 10/4/97 - began heavy inline documentation of the code. Corrected typos - * and spelling mistakes. - * 10/5/97 - added code to handle PHY interrupts, disable PHY on - * loss of link, and correctly re-enable PHY when link is - * re-established. (put back CFG_PHYIE) - * - * Modified to work with the IDT7721 nicstar -- AAL5 (tested) only. - * - * R. D. Rechenmacher , Aug. 6, 1997 - * - * Linux driver for the IDT77201 NICStAR PCI ATM controller. - * PHY component is expected to be 155 Mbps S/UNI-Lite or IDT 77155; - * see init_nicstar() for PHY initialization to change this. This driver - * expects the Linux ATM stack to support scatter-gather lists - * (skb->atm.iovcnt != 0) for Rx skb's passed to vcc->push. - * - * Implementing minimal-copy of received data: - * IDT always receives data into a small buffer, then large buffers - * as needed. This means that data must always be copied to create - * the linear buffer needed by most non-ATM protocol stacks (e.g. IP) - * Fix is simple: make large buffers large enough to hold entire - * SDU, and leave bytes empty at the start. Then - * copy small buffer contents to head of large buffer. - * Trick is to avoid fragmenting Linux, due to need for a lot of large - * buffers. This is done by 2 things: - * 1) skb->destructor / skb->atm.recycle_buffer - * combined, allow nicstar_free_rx_skb to be called to - * recycle large data buffers - * 2) skb_clone of received buffers - * See nicstar_free_rx_skb and linearize_buffer for implementation - * details. - * - * - * - * Copyright (c) 1996 University of Cambridge Computer Laboratory - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * M. Welsh, 6 July 1996 - * - * - */ -- 2.53.0